

sleeplocks — sleeplocks v1.1.2

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/README.md#L1 "View Source")

sleeplocks

===================================================================================================================

[![Build Status](https://img.shields.io/github/workflow/status/whitfin/sleeplocks/CI)](https://github.com/whitfin/sleeplocks/actions) [![Hex.pm Version](https://img.shields.io/hexpm/v/sleeplocks.svg)](https://hex.pm/packages/sleeplocks) [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://hexdocs.pm/sleeplocks/)

This library is designed to provide simple locking mechanisms in Erlang/Elixir, similar to

how spinlocks work in other languages - except using messages to communicate locking.

This is useful for libraries which require lock synchronization, without having to roll your

own (however simple). Locks can be held by arbitrary numbers of process, making it possible

to implement various throttling mechanisms.

Best of all, this library is tiny! It builds upon basic OTP principles to implement lock

behaviour via simple processes and message passing.

[installation](#installation)

 Installation

--------------------------------------------

### 

[rebar](#rebar)

 Rebar

Follow the instructons found [here](https://hex.pm/docs/rebar3_usage) to configure your

Rebar setup to use Hex as a dependency source, then you can grab it directly:

```

{deps,[

 % pulls the latest version

 sleeplocks,

 % to pull the latest version from github

 {sleeplocks, {git, "git://github.com/whitfin/sleeplocks.git"}}

]}.

```

### 

[mix](#mix)

 Mix

To install it for your project, you can pull it directly from Hex. Rather

than use the version shown below, you can use the latest version from

Hex (shown at the top of this README).

```

def deps do

 [{:sleeplocks, "~> 1.0"}]

end

```

[usage](#usage)

 Usage

-----------------------

Snippets below contain sample usage in both Erlang and Elixir, and cover most of the small

API space offered by `sleeplocks`. For a more complete example, scroll down!

### 

[erlang](#erlang)

 Erlang

```

% create a new single lock (with a name)

1> sleeplocks:new(1, [{name, {local, my\_lock}}]).

{ok,<0.179.0>}

% take ownership of the lock

2> sleeplocks:acquire(my\_lock).

ok

% release the current hold on a lock

3> sleeplocks:release(my\_lock).

ok

% attempt to acquire a lock (which will succeed)

4> sleeplocks:attempt(my\_lock).

ok

% now that it's taken, other attempts will fail

5> sleeplocks:attempt(my\_lock).

{error,unavailable}

% release the lock again

6> sleeplocks:release(my\_lock).

ok

% handle acquisition and locking automatically

7> sleeplocks:execute(my\_lock, fun() ->

7> 3

7> end).

3

```

### 

[elixir](#elixir)

 Elixir

```

# create a new single lock (with a name)

iex(1)> :sleeplocks.new(1, [ name: :my\_lock ])

{:ok, #PID<0.179.0>}

# take ownership of the lock

iex(2)> :sleeplocks.acquire(:my\_lock)

:ok

# release the current hold on a lock

iex(3)> :sleeplocks.release(:my\_lock)

:ok

# attempt to acquire a lock (which will succeed)

iex(4)> :sleeplocks.attempt(:my\_lock)

:ok

# now that it's taken, other attempts will fail

iex(5)> :sleeplocks.attempt(:my\_lock)

{:error, :unavailable}

# release the lock again

iex(6)> :sleeplocks.release(:my\_lock)

:ok

# handle acquisition and locking automatically

iex(7)> :sleeplocks.execute(:my\_lock, fn ->

iex(7)>  3

iex(7)> end)

3

```

[examples](#examples)

 Examples

--------------------------------

This example is in Elixir, but it should be fairly understandable for those coming from

both languages. It simply spawns 6 processes which each attempt to hold a lock for 10

seconds. As the lock is created with only 2 slots, this runs for 30 seconds and 2 of our

spawned tasks can hold the lock at any given time.

```

# First create a new lock, with 2 slots only

{:ok, ref} = :sleeplocks.new(2)

# Then spawn 6 tasks, which each just sleep for 10 seconds

# after acquiring the lock. This means that 2 processes will

# acquire a lock and then release after 10 seconds. This

# will repeat 3 times (6 / 2) until 30 seconds are up.

for idx <- 1..6 do

 Task.start(fn ->

 :sleeplocks.execute(ref, fn ->

 IO.puts("Locked #{idx}")

 Process.sleep(10\_000)

 IO.puts("Releasing #{idx}")

 end)

 end)

end

```

[← Previous Page

 

API Reference](api-reference.html)

[Next Page →

 

LICENSE](license.html)





sleeplocks — sleeplocks v1.1.2

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L13 "View Source")

sleeplocks

(sleeplocks v1.1.2)

=================================================================================================================================================

BEAM friendly spinlocks for Elixir/Erlang.

This module provides a very simple API for managing locks inside a BEAM instance. It's modeled on spinlocks, but works through message passing rather than loops. Locks can have multiple slots to enable arbitrary numbers of associated processes. The moment a slot is freed, the next awaiting process acquires the lock.

All of this is done in a simple Erlang process so there's very little dependency, and management is extremely simple.

 

[Link to this section](#summary)

 Summary

==========================================

[Types](#types)

----------------

[name/0](#t:name/0)

[start\_ret/0](#t:start_ret/0)

[Functions](#functions)

------------------------

[acquire(Name)](#acquire/1)

Acquires a lock for the current process.

[attempt(Name)](#attempt/1)

Attempts to acquire a lock for the current process.

[code\_change(Vsn, Lock, Extra)](#code_change/3)

[execute(Name, Exec)](#execute/2)

Executes a function when a lock can be acquired.

[handle\_call(\_, Caller, Lock)](#handle_call/3)

[handle\_cast(Msg, Lock)](#handle_cast/2)

[handle\_info(Msg, Lock)](#handle_info/2)

[init(Slots)](#init/1)

[new(Slots)](#new/1)

Creates a new lock with a provided concurrency factor.

[new(Slots, Args)](#new/2)

Creates a new lock with a provided concurrency factor.

[release(Name)](#release/1)

Releases a lock held by the current process.

[start\_link(Slots)](#start_link/1)

[start\_link(Slots, Args)](#start_link/2)

[terminate(Reason, Lock)](#terminate/2)

[Link to this section](#types)

Types

=====================================

[Link to this type](#t:name/0 "Link to this type")

name/0

======

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L27 "View Source")

```

-type name() ::

    atom() |

    {local, Name :: atom()} |

    {global, GlobalName :: any()} |

    {via, Module :: atom(), ViaName :: any()}.

```

[Link to this type](#t:start_ret/0 "Link to this type")

start\_ret/0

============

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L34 "View Source")

```

-type start_ret() :: {ok, pid()} | ignore | {error, term()}.

```

[Link to this section](#functions)

Functions

=============================================

[Link to this function](#acquire/1 "Link to this function")

acquire(Name)

=============

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L67 "View Source")

```

-spec acquire(Name :: [name](#t:name/0)()) -> ok.

```

Acquires a lock for the current process.

This will block until a lock can be acquired.

 

[Link to this function](#attempt/1 "Link to this function")

attempt(Name)

=============

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L76 "View Source")

```

-spec attempt(Name :: [name](#t:name/0)()) -> ok | {error, unavailable}.

```

Attempts to acquire a lock for the current process.

In the case there are no slots available, an error will be returned immediately rather than waiting.

 

[Link to this function](#code_change/3 "Link to this function")

code\_change(Vsn, Lock, Extra)

==============================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L168 "View Source")

[Link to this function](#execute/2 "Link to this function")

execute(Name, Exec)

===================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L85 "View Source")

```

-spec execute(Name :: [name](#t:name/0)(), Exec :: fun(() -> any())) -> any().

```

Executes a function when a lock can be acquired.

The lock is automatically released after the function has completed execution; there's no need to manually release.

 

[Link to this function](#handle_call/3 "Link to this function")

handle\_call(\_, Caller, Lock)

==============================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L122 "View Source")

[Link to this function](#handle_cast/2 "Link to this function")

handle\_cast(Msg, Lock)

=======================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L153 "View Source")

[Link to this function](#handle_info/2 "Link to this function")

handle\_info(Msg, Lock)

=======================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L158 "View Source")

[Link to this function](#init/1 "Link to this function")

init(Slots)

===========

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L117 "View Source")

[Link to this function](#new/1 "Link to this function")

new(Slots)

==========

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L43 "View Source")

```

-spec new(Slots :: pos_integer()) -> [start\_ret](#t:start_ret/0)().

```

Creates a new lock with a provided concurrency factor.

 

[Link to this function](#new/2 "Link to this function")

new(Slots, Args)

================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L49 "View Source")

```

-spec new(Slots :: pos_integer(), Args :: list()) -> [start\_ret](#t:start_ret/0)().

```

Creates a new lock with a provided concurrency factor.

 

[Link to this function](#release/1 "Link to this function")

release(Name)

=============

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L96 "View Source")

```

-spec release(Name :: [name](#t:name/0)()) -> ok.

```

Releases a lock held by the current process.

 

[Link to this function](#start_link/1 "Link to this function")

start\_link(Slots)

==================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L102 "View Source")

```

-spec start_link(Slots :: pos_integer()) -> [start\_ret](#t:start_ret/0)().

```

[Link to this function](#start_link/2 "Link to this function")

start\_link(Slots, Args)

========================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L108 "View Source")

```

-spec start_link(Slots :: pos_integer(), Args :: list()) -> [start\_ret](#t:start_ret/0)().

```

[Link to this function](#terminate/2 "Link to this function")

terminate(Reason, Lock)

=======================

[View Source](https://github.com/whitfin/sleeplocks/blob/v1.1.2/src/sleeplocks.erl#L163 "View Source")

