Synchronization Primitives for Elixir, such as CyclicBarrier
and CountDownLatch
.
These primitives allow you to synchronize multiple Elixir processes using higher-level abstractions than messages. I have found them are very useful in testing agent-based and mutli-process Elixir apps.
sync_primitives
is available on Hex. Add sync_primitives
to your list of dependencies in mix.exs
:
def deps do
[{:sync_primitives, "~> 0.1.0"}]
end
Documentation can be found at https://hexdocs.pm/sync_primitives.
-
Start a
CyclicBarrier
barrier = SyncPrimitives.CyclicBarrier.start(2, fn -> IO.puts("barrier action") end)
-
Start the processes you wish to synchronize through a CyclicBarrier.
-
The first process:
spawn_link(fn -> IO.puts("process 1, before wait") SyncPrimitives.CyclicBarrier.await(barrier) IO.puts("process 1, after wait") end)
-
Wait for a little bit to see that
process 1
won't reach the "after wait" message. -
Start the second process:
spawn_link(fn -> IO.puts("process 2, before wait") SyncPrimitives.CyclicBarrier.await(barrier) IO.puts("process 2, after wait") end)
-
-
All of above will output:
process 1, before wait process 2, before wait barrier action process 1, after wait process 2, after wait
-
Remember to stop the barrier
SyncPrimitives.CyclicBarrier.stop(barrier)
-
Start a
CountDownLatch
latch = SyncPrimitives.CountDownLatch.start(2, fn -> IO.puts("latch done") end)
-
Start the process you wish to block until the CountDownLatch is released.
spawn_link(fn -> IO.puts("before wait") SyncPrimitives.CountDownLatch.await(latch) IO.puts("after wait") end)
-
Wait for a little bit to see that the process won't reach the "after wait" message.
-
Countdown enough times for the latch to reach 0.
SyncPrimitives.CountDownLatch.count_down(latch) SyncPrimitives.CountDownLatch.count_down(latch)
-
All of above will output:
latch done after wait
-
Remember to stop the latch!
SyncPrimitives.CountDownLatch.stop(latch)