README.md

# sync_primitives for Elixir

[![Apache License](https://img.shields.io/hexpm/l/sync_primitives)](LICENSE.md)
[![Hex.pm](https://img.shields.io/hexpm/v/sync_primitives)](https://hex.pm/packages/sync_primitives)
[![Documentation](https://img.shields.io/badge/hexdocs-latest-blue.svg)](https://hexdocs.pm/sync_primitives/index.html)
[![Build Status](https://travis-ci.org/ianatha/sync_primitives.svg?branch=master)](https://travis-ci.org/ianatha/sync_primitives)
[![Coverage Status](https://coveralls.io/repos/github/ianatha/sync_primitives/badge.svg?branch=master)](https://coveralls.io/github/ianatha/sync_primitives?branch=master)

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.

## Installation

`sync_primitives` is available on [Hex](https://hex.pm/). Add `sync_primitives` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [{:sync_primitives, "~> 0.1.0"}]
end
```

Documentation can be found at [https://hexdocs.pm/sync_primitives](https://hexdocs.pm/sync_primitives).

## CyclicBarrier Usage

1. Start a `CyclicBarrier`
    ```elixir
    barrier = SyncPrimitives.CyclicBarrier.start(2, fn -> IO.puts("barrier action") end)
    ```

2. Start the processes you wish to synchronize through a CyclicBarrier.

    1. The first process:
        ```elixir
        spawn_link(fn ->
          IO.puts("process 1, before wait")
          SyncPrimitives.CyclicBarrier.await(barrier)
          IO.puts("process 1, after wait")
        end)
        ```


    2. Wait for a little bit to see that `process 1` won't reach the "after wait" message.


    3. Start the second process:
        ```elixir
        spawn_link(fn ->
          IO.puts("process 2, before wait")
          SyncPrimitives.CyclicBarrier.await(barrier)
          IO.puts("process 2, after wait")
        end)
        ```

3. All of above will output:
    ```
    process 1, before wait
    process 2, before wait
    barrier action
    process 1, after wait
    process 2, after wait
    ```

4. Remember to stop the barrier
    ```elixir
    SyncPrimitives.CyclicBarrier.stop(barrier)
    ```

## CountDownLatch Usage

1. Start a `CountDownLatch`
    ```elixir
    latch = SyncPrimitives.CountDownLatch.start(2, fn -> IO.puts("latch done") end)
    ```

2. Start the process you wish to block until the CountDownLatch is released.
    ```elixir
    spawn_link(fn ->
      IO.puts("before wait")
      SyncPrimitives.CountDownLatch.await(latch)
      IO.puts("after wait")
    end)
    ```

3. Wait for a little bit to see that the process won't reach the "after wait" message.

4. Countdown enough times for the latch to reach 0.
    ```elixir
    SyncPrimitives.CountDownLatch.count_down(latch)
    SyncPrimitives.CountDownLatch.count_down(latch)
    ```

3. All of above will output:
    ```
    latch done
    after wait
    ```

4. Remember to stop the latch!
    ```
    SyncPrimitives.CountDownLatch.stop(latch)
    ```