Copyright (c) 2016 Guilherme Andrade
Version: 3.1.1
Authors: Guilherme Andrade (vegrandis(at)gandrade(dot)net
).
vegrandis
: Atomic shared variables for Erlang
vegrandis
provides atomic variables - for both native integral types and Erlang terms - and native flags that can be shared between Erlang processes living in the same node.
It consists of a NIF library wrapping around C++11's std::atomic; a majority of the standard integral data types can be used and most of the original operations can be performed, including optionally specifying memory ordering constraints and, if both hardware and compiler implementation allow it, operating in a lockfree fashion.
Any allocated variables will be automatically deallocated by the garbage collector once there are no more references to it.
Original development rig runs OTP 17.5 over GNU/Linux x86_64, and quick test with OTP 17.5 over GNU/Linux ARM was also successful; other platforms have not been tested. Building dependencies include make
and g++
(but there's no reason clang
won't work as well.)
SharedTerm = vegrandis:new(),
vegrandis:store(SharedTerm, math:pi()),
spawn(fun () ->
io:format("stored value: ~p~n", [vegrandis:load(SharedTerm)])
end).
% stored value: 3.141592653589793
AtomicCounter = vegrandis:new(uint8),
Increments = 10,
Parent = self(),
[spawn(
fun () ->
Parent ! vegrandis:fetch_add(AtomicCounter, 1)
end)
|| _ <- lists:seq(1, Increments)],
% [0,1,2,3,4,5,6,7,8,9]
[receive Value -> Value end || _ <- lists:seq(1, Increments)],
% 10
vegrandis:load(AtomicCounter).
AtomicCounter = vegrandis:new(int_fast32),
vegrandis:store(AtomicCounter, 123),
[spawn(
fun F() ->
Value = vegrandis:load(AtomicCounter, memory_order_relaxed),
case vegrandis:compare_exchange_weak(AtomicCounter,
Value, Value + 1, memory_order_release, memory_order_relaxed)
of
true ->
ok;
{false, ChangedValue} ->
F()
end
end)
|| _ <- lists:seq(1, 100)],
timer:sleep(1000),
vegrandis:load(AtomicCounter). % 223
AtomicFlag = vegrandis_flag:new(),
[spawn(
fun F() ->
case vegrandis_flag:test_and_set(AtomicFlag) of
false ->
io:format("~p acquired spinlock~n", [self()]),
vegrandis_flag:clear(AtomicFlag),
io:format("~p cleared spinlock~n", [self()]);
true ->
F()
end
end)
|| _ <- lists:seq(1, 10)].
AtomicCounter = vegrandis:new(long),
vegrandis:is_lock_free(AtomicCounter) orelse exit(this_wont_do).
- term (any Erlang term)
- int8
- uint8
- int16
- uint16
- int32
- uint32
- int64
- uint64
- char
- schar
- uchar
- short
- ushort
- int
- uint
- long
- ulong
- llong
- ullong
- char16
- char32
- wchar
- int_least8
- uint_least8
- int_least16
- uint_least16
- int_least32
- uint_least32
- int_least64
- uint_least64
- int_fast8
- uint_fast8
- int_fast16
- uint_fast16
- int_fast32
- uint_fast32
- int_fast64
- uint_fast64
- intmax
- uintmax
- memory_order_relaxed
- memory_order_consume
- memory_order_acquire
- memory_order_release
- memory_order_acq_rel
- memory_order_seq_cst
- Unit tests
- Clean up C++ code / look for alternatives to the current template hell
- Support named variables (in ETS fashion)
vegrandis |
vegrandis_flag |