Skip to content
This repository has been archived by the owner on Jun 21, 2018. It is now read-only.

g-andrade/vegrandis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vegrandis

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)

Modules

vegrandis
vegrandis_flag