# `Agentic.Concurrency.Semaphore`

Bounded concurrency semaphore using a GenServer.

Ported from SCE. Limits the number of concurrent tasks that can hold permits.
Automatically releases permits when the holding process crashes.

## Usage

    {:ok, sem} = Semaphore.start_link(limit: 5)
    :ok = Semaphore.acquire(sem)
    # do work
    :ok = Semaphore.release(sem)

Or with automatic release:

    Semaphore.with_permit(sem, fn ->
      # do work — permit auto-released on return or crash
    end)

# `t`

```elixir
@type t() :: %Agentic.Concurrency.Semaphore{
  available: non_neg_integer(),
  limit: pos_integer(),
  monitors: %{required(reference()) =&gt; pid()},
  queue: :queue.queue(),
  stats: %{total_acquired: non_neg_integer(), total_released: non_neg_integer()}
}
```

# `acquire`

Acquire a permit. Blocks if none available. Returns `:ok`. Times out after 5 seconds by default.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `limit`

Get the concurrency limit.

# `release`

Release a permit. Returns `:ok`.

# `start_link`

Start a semaphore with the given concurrency limit.

# `stats`

Get current stats.

# `with_permit`

Execute a function with an automatically managed permit.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
