{"id":13735839,"url":"https://github.com/elijahr/lockfreequeues","last_synced_at":"2026-05-01T07:04:59.880Z","repository":{"id":45423897,"uuid":"276770166","full_name":"elijahr/lockfreequeues","owner":"elijahr","description":"Lock-free queue implementations for Nim.","archived":false,"fork":false,"pushed_at":"2026-04-26T09:35:01.000Z","size":1297,"stargazers_count":47,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"devel","last_synced_at":"2026-04-26T10:16:12.606Z","etag":null,"topics":["circular-buffer","lock-free","mpmc","mpsc","nim","queue","ring-buffer","spsc"],"latest_commit_sha":null,"homepage":"","language":"Nim","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elijahr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2020-07-03T00:20:00.000Z","updated_at":"2026-02-12T17:34:24.000Z","dependencies_parsed_at":"2024-01-12T03:36:36.149Z","dependency_job_id":"1d2b52b0-c738-4c75-af20-dc04b8840c37","html_url":"https://github.com/elijahr/lockfreequeues","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/elijahr/lockfreequeues","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elijahr%2Flockfreequeues","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elijahr%2Flockfreequeues/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elijahr%2Flockfreequeues/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elijahr%2Flockfreequeues/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elijahr","download_url":"https://codeload.github.com/elijahr/lockfreequeues/tar.gz/refs/heads/devel","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elijahr%2Flockfreequeues/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32487746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circular-buffer","lock-free","mpmc","mpsc","nim","queue","ring-buffer","spsc"],"created_at":"2024-08-03T03:01:11.898Z","updated_at":"2026-05-01T07:04:59.875Z","avatar_url":"https://github.com/elijahr.png","language":"Nim","funding_links":[],"categories":["Operating System"],"sub_categories":["IO"],"readme":"[![build](https://github.com/elijahr/lockfreequeues/actions/workflows/build.yml/badge.svg)](https://github.com/elijahr/lockfreequeues/actions/workflows/build.yml)\n\n# lockfreequeues\n\nLock-free queues for Nim. Bounded queues are ring buffers; unbounded queues are\nlinked segments reclaimed via [DEBRA](https://github.com/elijahr/nim-debra).\nAll variants cover SPSC, SPMC, MPSC, and MPMC.\n\nAPI documentation: \u003chttps://elijahr.github.io/lockfreequeues\u003e\n\n## Why this library\n\nIf two threads need to hand items to each other and you cannot afford a mutex,\nthe answer is a lock-free queue. Picking the right one is the hard part: do you\nhave one producer or many, one consumer or many, a fixed capacity or not? Each\nchoice changes the algorithm and the cost. `lockfreequeues` ships eight queues\ncovering every cell of that grid, with a uniform API and verified ordering\nguarantees.\n\nA short vocabulary first.\n\n- **Wait-free**: every thread completes its operation in a bounded number of\n  steps, regardless of what other threads do. The strongest progress guarantee.\n- **Lock-free**: at least one thread makes progress on every step. Individual\n  threads may retry, but the system never stalls.\n\nWait-free is preferable when you can get it; lock-free is what you get with\ncontended CAS loops. Both are stronger than mutex-based code, which can stall\nthe whole system if a holder is preempted.\n\n## Installation\n\n```sh\nnimble install lockfreequeues\n```\n\n## Quick Start\n\n### Bounded SPSC\n\n```nim\nimport options\nimport lockfreequeues\n\n# Bounded single-producer, single-consumer queue, capacity 16\nvar queue = initSipsic[16, int]()\n\ndiscard queue.push(42)\ndiscard queue.push(123)\n\nlet item = queue.pop()  # some(42)\nassert item == some(42)\n```\n\n### Unbounded MPMC\n\nThe MP/MC unbounded variants need a `DebraManager` for safe segment\nreclamation and a per-thread handle for every producer and consumer.\n\n```nim\nimport options\nimport debra\nimport lockfreequeues\n\nvar manager = initDebraManager[4]()\nvar queue = newUnboundedMupmuc[64, int, 4](addr manager)\n\nlet producerHandle = registerThread(manager)\nlet consumerHandle = registerThread(manager)\n\nvar producer = queue.getProducer(producerHandle)\nvar consumer = queue.getConsumer(consumerHandle)\n\nproducer.push(42)\nlet item = consumer.pop()  # some(42)\nassert item == some(42)\n```\n\nSee [`examples/`](examples/) for full multi-threaded examples and patterns\n(audio buffer, job scheduler, event collector, task fan-out).\n\n## Choosing a queue\n\n| Queue              | P    | C    | Push      | Pop       | Bounded? | Needs `DebraManager`? | Per-thread handle? |\n|--------------------|------|------|-----------|-----------|----------|-----------------------|--------------------|\n| `Sipsic`           | 1    | 1    | wait-free | wait-free | yes      | no                    | no                 |\n| `Sipmuc`           | 1    | many | wait-free | lock-free | yes      | no                    | no                 |\n| `Mupsic`           | many | 1    | lock-free | wait-free | yes      | no                    | no                 |\n| `Mupmuc`           | many | many | lock-free | lock-free | yes      | no                    | no                 |\n| `UnboundedSipsic`  | 1    | 1    | wait-free | wait-free | no       | no                    | no                 |\n| `UnboundedSipmuc`  | 1    | many | wait-free | lock-free | no       | yes                   | consumer side      |\n| `UnboundedMupsic`  | many | 1    | lock-free | wait-free | no       | yes                   | producer side      |\n| `UnboundedMupmuc`  | many | many | lock-free | lock-free | no       | yes                   | both               |\n\n`UnboundedSipsic` is special: with one producer and one consumer the consumer\nis the only freer, so it does not need DEBRA. Every other unbounded variant\ndoes, because multiple threads can race to detach a segment.\n\n### Bounded vs unbounded\n\nBounded queues are ring buffers with compile-time capacity. Use them when:\n\n- memory usage must be predictable;\n- you are working in embedded or real-time systems;\n- producer and consumer counts are known at compile time.\n\nUnbounded queues are linked segments that grow as needed. Use them when:\n\n- workload is bursty or unpredictable;\n- producer or consumer threads are created dynamically;\n- some memory growth is acceptable in exchange for never blocking on a full queue.\n\n## Dependencies\n\n- [`debra`](https://github.com/elijahr/nim-debra) `\u003e= 0.3.0` for epoch-based\n  reclamation in the unbounded multi-thread queues. `nim-debra` is a\n  general-purpose DEBRA+ implementation; nothing about it is specific to this\n  library, and it can be reused as the reclamation backend for any lock-free\n  data structure you build.\n- [`typestates`](https://github.com/elijahr/nim-typestates) `\u003e= 0.3.1` for the\n  slot-ownership state machines that back push and pop.\n\n## Compile-time options\n\n| Flag                                       | Default | Effect                                                                                  |\n|--------------------------------------------|---------|-----------------------------------------------------------------------------------------|\n| `-d:allowNonLockFreeQueueItems`            | off     | Disable the arc/orc compile-time check that rejects `ref` item types.                   |\n| `-d:nimEnforceLockFreeAtomics`             | off     | Nim flag; fail compilation if any atomic operation falls back to spinlocks.             |\n| `-d:LockFreeQueuesAdvanceEvery=N`          | 64      | DEBRA epoch-advance cadence for unbounded queues' Eager reclamation per-pop fast path.  |\n\n## Thread safety\n\nThe one rule that bites first: on `arc` / `orc`, `ref` item types fail to\ncompile. Reference counting on those memory managers can fall back to\nspinlocks, which would defeat the lock-free guarantee. Use a value type, a\n`ptr T`, or compile with `-d:allowNonLockFreeQueueItems` if you accept the\ntrade-off.\n\nThe full safety model — slot-ownership typestates, why the queue itself is\nlock-free even when items are not, and the matrix of MM x sanitiser\ncombinations under CI — lives in\n[`docs/safety-model.md`](docs/safety-model.md). The typestate transitions are\ndocumented in\n[`docs/slot-ownership-typestates.md`](docs/slot-ownership-typestates.md).\n\n## Benchmarks\n\nThroughput and latency results are checked into\n[`benchmarks/results/latest.json`](benchmarks/results/latest.json) and rendered\ninto the table below. Re-run the suite with `nimble benchmarks`, then update\nthis section with `nim r benchmarks/render_readme.nim`.\n\n\u003c!-- BENCHMARKS:start --\u003e\n_Platform: macosx arm64, 8 cores, 2025-12-03T22:24:55Z._\n\n| implementation | threads | throughput (ops/ms) | p50 latency (ns) |\n|----------------|---------|---------------------|------------------|\n| `lockfreequeues/Sipsic` | 1P/1C | 7411.0 | 292 |\n| `nim/channels` | 1P/1C | 1199.7 | — |\n| `nim/channels` | 2P/2C | 815.8 | — |\n| `nim/channels` | 4P/4C | 1779.5 | — |\n\n_Numbers regenerated by `nim r benchmarks/render_readme.nim` from `benchmarks/results/latest.json`._\n\n\u003c!-- BENCHMARKS:end --\u003e\n\nSee [`benchmarks/`](benchmarks/) for the full suite, methodology, and\nadapter implementations.\n\n## Examples\n\nExamples are in [`examples/`](examples/) and can be run with:\n\n```sh\nnimble examples\n```\n\n## Running tests\n\n```sh\nnimble test\n```\n\nCI (see [`.github/workflows/build.yml`](.github/workflows/build.yml)) runs the\nsuite on:\n\n- Runners: `ubuntu-24.04` (x86_64), `ubuntu-24.04-arm` (native arm64),\n  `macos-latest` (arm64).\n- Memory managers: `arc`, `orc`, `refc`, `atomicArc`.\n- Backends: C and C++.\n- Sanitisers: ThreadSanitizer (TSAN) on `atomicArc`, AddressSanitizer (ASAN).\n- Lock-free atomic enforcement: `-d:nimEnforceLockFreeAtomics` lane on `arc`\n  and `orc`.\n\n192 tests across the bounded, unbounded, threaded, and lock-free-check suites.\n\n## Contributing\n\nPull requests and issues welcome. See\n[CONTRIBUTING.md](CONTRIBUTING.md) for the contribution workflow.\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md). The current release is\n[3.2.0](CHANGELOG.md#320---2026-04-27).\n\n## References\n\n- Juho Snellman, [\"I've been writing ring buffers wrong all these years\"](https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/)\n  ([alt](https://web.archive.org/web/20200530040210/https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/)).\n- Mamy Ratsimbazafy, [research on SPSC channels](https://github.com/mratsim/weave/blob/master/weave/cross_thread_com/channels_spsc.md#litterature)\n  for weave.\n- Henrique F. Bucher, [\"Yes, You Have Been Writing SPSC Queues Wrong Your Entire Life\"](http://www.vitorian.com/x1/archives/370)\n  ([alt](https://web.archive.org/web/20191225164231/http://www.vitorian.com/x1/archives/370)).\n- Maged M. Michael and Michael L. Scott, \"Simple, Fast, and Practical\n  Non-Blocking and Blocking Concurrent Queue Algorithms\" (PODC 1996).\n- Dmitry Vyukov's writings on bounded MPMC ring buffers and CAS-based\n  coordination patterns.\n- Trevor Brown, [\"Reclaiming Memory for Lock-Free Data Structures: There has to\n  be a Better Way\"](https://www.cs.utoronto.ca/~tabrown/debra/) (DEBRA, the\n  reclamation scheme used by the unbounded queues).\n\nMany thanks to Mamy Ratsimbazafy for reviewing the initial release and\noffering suggestions.\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felijahr%2Flockfreequeues","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felijahr%2Flockfreequeues","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felijahr%2Flockfreequeues/lists"}