{"id":19005900,"url":"https://github.com/rbeeli/posixipc.jl","last_synced_at":"2026-02-25T22:33:21.230Z","repository":{"id":228926451,"uuid":"775007190","full_name":"rbeeli/PosixIPC.jl","owner":"rbeeli","description":"Fast single-producer, single-consumer queue implementation in Julia.","archived":false,"fork":false,"pushed_at":"2025-07-14T23:46:20.000Z","size":69,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-15T04:03:47.324Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Julia","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/rbeeli.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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-20T15:40:48.000Z","updated_at":"2025-07-14T23:46:25.000Z","dependencies_parsed_at":"2024-03-29T01:26:58.212Z","dependency_job_id":"aa8e770d-9bcd-4414-a636-b036df9ed9f4","html_url":"https://github.com/rbeeli/PosixIPC.jl","commit_stats":null,"previous_names":["rbeeli/spscqueue.jl"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rbeeli/PosixIPC.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbeeli%2FPosixIPC.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbeeli%2FPosixIPC.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbeeli%2FPosixIPC.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbeeli%2FPosixIPC.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rbeeli","download_url":"https://codeload.github.com/rbeeli/PosixIPC.jl/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rbeeli%2FPosixIPC.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29843469,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-25T21:18:31.832Z","status":"ssl_error","status_checked_at":"2026-02-25T21:18:29.265Z","response_time":61,"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":[],"created_at":"2024-11-08T18:29:35.083Z","updated_at":"2026-02-25T22:33:21.218Z","avatar_url":"https://github.com/rbeeli.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PosixIPC.jl\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![](https://img.shields.io/badge/Version-beta-blue)\n\nThis library implements a set of POSIX-compliant inter-process communication (IPC) mechanisms and relevant helper functions in Julia.\n\n## SPSC queue\n\nThe Single-Producer Single-Consumer (SPSC) queue allows to push variable-sized binary messages into a queue from one thread, and pop them from another thread.\n\nFor inter-process communication, the queue can be used in shared memory.\n\nThe queue is lock-free and uses a circular buffer to store the messages and their payloads in a contiguous memory block.\n\nThe queue memory can be used directly by the consumer as long as the dequeue-operation hasn't been committed (see `dequeue_commit!`), which allows for zero-copy message passing.\n\n## Publish-Subscribe (PubSub)\n\nThe Publish-Subscribe (PubSub) mechanism allows multiple subscribers to receive messages from a single publisher (one-to-many communication, fan-out).\nThis is implemented using a dedicated SPSC queue for each subscriber. The publisher enqueues messages into all subscriber SPSC queues sequentially.\n\n## Performance\n\nOn a 12th Gen Intel(R) Core(TM) i9-12900K running Ubuntu 22.04 x64, the SPSC queue can:\n\n- enqueue and dequeue way above 200 million 8-byte messages per second\n- achieve latencies of \u003c 100 nanoseconds in the non-contended case (producer slower than consumer, consumer busy spinning)\n\nThe queue buffer memory can be allocated on the heap, or in shared memory (see `SPSCStorage`).\n\n## API\n\n### SPSCQueue\n\nThe queue is implemented in the `SPSCQueue` module and provides the following functions:\n\n```julia\nusing PosixIPC.Queues\nusing PosixIPC.Queues.SPSC\n\n# constructor: Create storage memory on heap\nSPSCStorage(storage_size::Integer)\n\n# constructor: Create new storage from `Ptr{UInt8}` pointer\nSPSCStorage(ptr::Ptr{T}, storage_size::Integer; finalizer_fn::Function)\n\n# constructor: Opens existing storage buffer from an `UInt8` pointer\nSPSCStorage(ptr::Ptr{T}; finalizer_fn::Function)\n\n# constructor: Create an instance of a Single-Producer Single-Consumer (SPSC) queue with variable-sized message buffer.\nSPSCQueueVar(storage::SPSCStorage)\n\n# Enqueues a message in the queue. Returns `true` if successful, `false` if the queue is full.\nenqueue!(queue::SPSCQueueVar, msg::Message)::Bool\n\n# Reads the next message from the queue.\n# Returns a message view with `size = 0` if the queue is empty (`SPSC_MESSAGE_VIEW_EMPTY`).\n# Call `isempty(msg)` to check if a message was dequeued successfully.\n# The reader only advances after calling `dequeue_commit!`, this allows to use the\n# message view without copying the data to another buffer between `dequeue_begin!` and `dequeue_commit!`.\n# Failing to call `dequeue_commit!` is allowed, but means the reader will not advance.\ndequeue_begin!(queue::SPSCQueueVar)::MessageView\n\n# Moves the reader index to the next message in the queue.\n# Call this after processing a message returned by `dequeue_begin!`.\n# The message view is no longer valid after this call.\ndequeue_commit!(queue::SPSCQueueVar, msg_view::MessageView)::Nothing\n\n# Returns `true` if the message view is empty (size is 0), implying that the queue is empty.\nisempty(msg_view::MessageView)::Bool\n\n# Returns `true` if the SPSC queue is empty.\n# Does not dequeue any messages (read-only operation).\n# There is no guarantee that the queue is still empty after this function returns,\n# as the writer might have enqueued a message immediately after the check.\nisempty(queue::SPSCQueueVar)::Bool\n\n# Returns `false` if the SPSC queue is empty.\n# Does not dequeue any messages (read-only operation).\n# To be used by consumer thread only due to memory order optimization.\ncan_dequeue(queue::SPSCQueueVar)::Bool\n```\n\n### PubSub\n\nThe Publish-Subscribe (PubSub) mechanism is implemented in the `PubSub` module and provides the following functions:\n\n```julia\nusing PosixIPC.SharedMemory\nusing PosixIPC.Queues\nusing PosixIPC.Queues.PubSub\n\nPubSubConfig(\n    shm_name::String,\n    storage_size_bytes::Int\n    ;\n    queue_full_policy::QueueFullPolicy.T,\n    log_message_drop::Bool=true\n)\n\n# Creates a new instance of a Publish-Subscribe (PubSub) hub.\nPubSubHub()\n\n# Synchronizes list of PubSub configurations with the PubSubHub.\n# This function should be called by the publisher to update the list of subscribers\n# and their SPSC queues.\nsync_configs!(ps::PubSubHub, configs::Vector{PubSubConfig})::Nothing\n\n# Publishes a message to all subscribers and enqueues it in their SPSC queues.\npublish!(ps::PubSubHub, val::Message)::Bool\n```\n\n### SharedMemory\n\nThe `SharedMemory` module provides helper functions to work with shared memory on POSIX-compliant systems.\n\n```julia\nusing PosixIPC.SharedMemory\n\n# Open or create a shared memory object.\nshm_open(\n    shm_name::String\n    ;\n    shm_flags=Base.Filesystem.JL_O_RDWR,\n    shm_mode=0o666,\n    size=-1,\n    verbose::Bool=false\n)::PosixSharedMemory\n\n# Delete a shared memory object (incl. the data).\nshm_unlink(shm::PosixSharedMemory)::Nothing\n\n# Close file descriptor of shared memory object.\nshm_close(shm::PosixSharedMemory)::Nothing\n```\n\n### Memory\n\nThe `Memory` module provides helper functions to work with aligned memory.\n\n```julia\nusing PosixIPC.Memory\n\n# Allocate aligned memory block.\naligned_alloc(size::Integer, alignment::Integer)::Ptr{Cvoid}\n\n# Free aligned memory block.\naligned_free(ptr::Ptr{UInt8})::Nothing\n```\n\n## Examples\n\nThe following example creates a SPSC queue with a fixed-size ring buffer of 100,000 bytes.\nThe queue itself allows to push and pop variable-sized messages. We send 1,000,000 messages from the producer to the consumer, and print the status every 10,000 messages.\n\n### SPSCQueue\n\n```julia\nusing ThreadPinning\nusing PosixIPC.Queues\nusing PosixIPC.Queues.SPSC\n\nfunction producer(queue::SPSCQueueVar, iterations::Int64)\n    println(\"producer started\")\n\n    # 8 bytes message\n    size = 8\n    data = Int64[0]\n    GC.@preserve data begin\n        data_ptr = pointer(data)\n        msg = Message(data_ptr, size)\n        for counter in 1:iterations\n            # store counter value in message\n            unsafe_store!(data_ptr, counter)\n\n            # enqueue message\n            while !enqueue!(queue, msg)\n                # queue full - busy wait\n            end\n\n            # print status\n            if counter % 10_000 == 0\n                println(\"\u003e sent $counter\")\n            end\n        end\n    end\n\n    println(\"producer done\")\nend\n\nfunction consumer(queue::SPSCQueueVar, iterations::Int64)\n    println(\"consumer started\")\n\n    counter = 0\n    while counter \u003c iterations\n        msg_view = dequeue_begin!(queue)\n        if !isempty(msg_view)\n            # get counter value from message\n            counter = unsafe_load(reinterpret(Ptr{Int64}, msg_view.data))\n\n            # commit message\n            dequeue_commit!(queue, msg_view)\n\n            # print status\n            if counter % 10_000 == 0\n                println(\"\u003c received $counter\")\n            end\n        end\n    end\n\n    println(\"consumer done\")\nend\n\nfunction run()\n    buffer_size = 100_000 # bytes\n    storage = SPSCStorage(buffer_size)\n\n    # create variable-element size SPSC queue\n    queue = SPSCQueueVar(storage)\n\n    # spawn producer and consumer threads, pin them to cores 3 and 5\n    iterations = 1_000_000\n    p_thread = ThreadPinning.@spawnat 3 producer(queue, iterations) # 1-based indexing\n    c_thread = ThreadPinning.@spawnat 5 consumer(queue, iterations) # 1-based indexing\n\n    wait(p_thread)\n    wait(c_thread)\nend\n\nrun()\n```\n\n### Shared memory\n\nThe queue storage can be allocated in shared memory, which allows to use the queue for inter-process communication.\nInstead of using `SPSCStorage(buffer_size)`, use `SPSCStorage(ptr, storage_size; finalizer_fn)` to create the storage from a pointer to shared memory.\n\n`SPSCStorage` can work with arbitrary `Ptr{T}` types.\nIt is the user's responsibility to manage the shared memory and provide the correct pointer and size.\nOptionally, a finalizer function can be provided to clean up the shared memory when the storage is no longer needed.\n\nExample of creating a `SPSCStorage` object in shared memory for a SPSC queue:\n\n```julia\nusing PosixIPC.SharedMemory\nusing PosixIPC.Queues.SPSC\n\nbuffer_size = 100_000 # bytes\nshm_size = buffer_size + SPSC_STORAGE_BUFFER_OFFSET\n\n# works only on Linux (see test/shm.jl for details)\nshm = shm_open(\n    \"spscqueue_jl_shared_memory\",\n    oflag=Base.Filesystem.JL_O_CREAT |\n          Base.Filesystem.JL_O_RDWR |\n          Base.Filesystem.JL_O_TRUNC,\n    mode=0o666,\n    size=shm_size\n)\nstorage = SPSCStorage(shm.ptr, shm.size)\n```\n\nSee [examples/shared_memory.jl](examples/shared_memory.jl) for the example file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frbeeli%2Fposixipc.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frbeeli%2Fposixipc.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frbeeli%2Fposixipc.jl/lists"}