{"id":44610428,"url":"https://github.com/rmind/ringbuf","last_synced_at":"2026-02-26T22:01:20.868Z","repository":{"id":70507427,"uuid":"58323475","full_name":"rmind/ringbuf","owner":"rmind","description":"Lock-free ring buffer (MPSC)","archived":false,"fork":false,"pushed_at":"2019-12-16T11:32:56.000Z","size":44,"stargazers_count":418,"open_issues_count":4,"forks_count":66,"subscribers_count":23,"default_branch":"master","last_synced_at":"2023-10-20T22:51:35.495Z","etag":null,"topics":["algorithm","c","library","lock-free","ring-buffer"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rmind.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-05-08T17:35:40.000Z","updated_at":"2023-10-20T22:51:35.843Z","dependencies_parsed_at":"2023-03-08T09:45:33.632Z","dependency_job_id":null,"html_url":"https://github.com/rmind/ringbuf","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"purl":"pkg:github/rmind/ringbuf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmind%2Fringbuf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmind%2Fringbuf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmind%2Fringbuf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmind%2Fringbuf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rmind","download_url":"https://codeload.github.com/rmind/ringbuf/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rmind%2Fringbuf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29874453,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T21:05:00.265Z","status":"ssl_error","status_checked_at":"2026-02-26T20:57:13.669Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["algorithm","c","library","lock-free","ring-buffer"],"created_at":"2026-02-14T12:00:22.735Z","updated_at":"2026-02-26T22:01:20.861Z","avatar_url":"https://github.com/rmind.png","language":"C","readme":"# Lock-free ring buffer\n\n[![Build Status](https://travis-ci.org/rmind/ringbuf.svg?branch=master)](https://travis-ci.org/rmind/ringbuf)\n\nLock-free multi-producer single-consumer (MPSC) ring buffer which supports\ncontiguous range operations and which can be conveniently used for message\npassing.  The implementation is written in C11 and distributed under the\n2-clause BSD license.\n\n## API\n\n* `int ringbuf_setup(ringbuf_t *rbuf, unsigned nworkers, size_t length)`\n  * Setup a new ring buffer of a given _length_.  The `rbuf` is a pointer\n  to the opaque ring buffer object; the caller is responsible to allocate\n  the space for this object.  Typically, the object would be allocated\n  dynamically if using threads or reserved in a shared memory blocked if\n  using processes.  The allocation size for the object shall be obtained\n  using the `ringbuf_get_sizes` function.  Returns 0 on success and -1\n  on failure.\n\n* `void ringbuf_get_sizes(unsigned nworkers, size_t *ringbuf_obj_size, size_t *ringbuf_worker_size)`\n  * Returns the size of the opaque `ringbuf_t` and, optionally, `ringbuf_worker_t` structures.\n  The size of the `ringbuf_t` structure depends on the number of workers,\n  specified by the `nworkers` parameter.\n\n* `ringbuf_worker_t *ringbuf_register(ringbuf_t *rbuf, unsigned i)`\n  * Register the current worker (thread or process) as a producer.  Each\n  producer MUST register itself.  The `i` is a worker number, starting\n  from zero (i.e. shall be than `nworkers` used in the setup).  On success,\n  returns a pointer to an opaque `ringbuf_worker_t` structured, which is\n  a part of the `ringbuf_t` memory block.  On failure, returns `NULL`.\n\n* `void ringbuf_unregister(ringbuf_t *rbuf, ringbuf_worker_t *worker)`\n  * Unregister the specified worker from the list of producers.\n\n* `ssize_t ringbuf_acquire(ringbuf_t *rbuf, ringbuf_worker_t *worker, size_t len)`\n  * Request a space of a given length in the ring buffer.  Returns the\n  offset at which the space is available or -1 on failure.  Once the data\n  is ready (typically, when writing to the ring buffer is complete), the\n  `ringbuf_produce` function must be called to indicate that.  Nested\n  acquire calls are not allowed.\n\n* `void ringbuf_produce(ringbuf_t *rbuf, ringbuf_worker_t *worker)`\n  * Indicate that the acquired range in the buffer is produced and is ready\n  to be consumed.\n\n* `size_t ringbuf_consume(ringbuf_t *rbuf, size_t *offset)`\n  * Get a contiguous range which is ready to be consumed.  Returns zero\n  if there is no data available for consumption.  Once the data is\n  consumed (typically, when reading from the ring buffer is complete),\n  the `ringbuf_release` function must be called to indicate that.\n\n* `void ringbuf_release(ringbuf_t *rbuf, size_t nbytes)`\n  * Indicate that the consumed range can now be released and may now be\n  reused by the producers.\n\n## Notes\n\nThe consumer will return a contiguous block of ranges produced i.e. the\n`ringbuf_consume` call will not return partial ranges.  If you think of\nproduced range as a message, then consumer will return a block of messages,\nalways ending at the message boundary.  Such behaviour allows us to use\nthis ring buffer implementation as a message queue.\n\nThe implementation was extensively tested on a 24-core x86 machine,\nsee [the stress test](src/t_stress.c) for the details on the technique.\nIt also provides an example how the mechanism can be used for message\npassing.\n\n## Caveats\n\nThis ring buffer implementation always provides a contiguous range of\nspace for the producer.  It is achieved by an early wrap-around if the\nrequested range cannot fit in the end.  The implication of this is that\nthe `ringbuf_acquire` call may fail if the requested range is greater\nthan half of the buffer size.  Hence, it may be necessary to ensure that\nthe ring buffer size is at least twice as large as the maximum production\nunit size.\n\nIt should also be noted that one of the trade-offs of such design is that\nthe consumer currently performs an O(n) scan on the list of producers.\n\n## Example\n\nProducers:\n```c\nif ((w = ringbuf_register(r, worker_id)) == NULL)\n\terr(EXIT_FAILURE, \"ringbuf_register\")\n\n...\n\nif ((off = ringbuf_acquire(r, w, len)) != -1) {\n\tmemcpy(\u0026buf[off], payload, len);\n\tringbuf_produce(r, tls);\n}\n```\n\nConsumer:\n```c\nif ((len = ringbuf_consume(r, \u0026off)) != 0) {\n\tprocess(\u0026buf[off], len);\n\tringbuf_release(r, len);\n}\n```\n","funding_links":[],"categories":["C"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmind%2Fringbuf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frmind%2Fringbuf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frmind%2Fringbuf/lists"}