{"id":20795892,"url":"https://github.com/g41797/mailbox","last_synced_at":"2025-04-09T19:23:31.210Z","repository":{"id":250991458,"uuid":"836068877","full_name":"g41797/mailbox","owner":"g41797","description":"Zig Mailbox  is convenient  inter-thread communication mechanizm.","archived":false,"fork":false,"pushed_at":"2024-10-22T16:32:17.000Z","size":375,"stargazers_count":47,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-23T21:22:28.265Z","etag":null,"topics":["actor-model","channel-on-steroids","fan-in","fan-out","inter-thread-communication","mailbox","thread-safe","zig","zig-library","zig-package"],"latest_commit_sha":null,"homepage":"","language":"Zig","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/g41797.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}},"created_at":"2024-07-31T05:20:32.000Z","updated_at":"2025-03-18T21:21:44.000Z","dependencies_parsed_at":"2024-10-23T04:45:29.046Z","dependency_job_id":null,"html_url":"https://github.com/g41797/mailbox","commit_stats":null,"previous_names":["g41797/yazq","g41797/mailbox"],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/g41797%2Fmailbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/g41797%2Fmailbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/g41797%2Fmailbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/g41797%2Fmailbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/g41797","download_url":"https://codeload.github.com/g41797/mailbox/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248095987,"owners_count":21046959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["actor-model","channel-on-steroids","fan-in","fan-out","inter-thread-communication","mailbox","thread-safe","zig","zig-library","zig-package"],"created_at":"2024-11-17T16:24:34.300Z","updated_at":"2025-04-09T19:23:31.187Z","avatar_url":"https://github.com/g41797.png","language":"Zig","readme":"![](_logo/mailboxes.png)\n\n\n# Mailbox - old new way of inter-thread communication.          \n\n[![CI](https://github.com/g41797/yazq/actions/workflows/ci.yml/badge.svg)](https://github.com/g41797/yazq/actions/workflows/ci.yml)\n\u003cimg src=\"https://img.shields.io/badge/Linux-FCC624?style=flat\u0026logo=linux\u0026logoColor=black\" width=\"48\" height=\"24\"\u003e\u0026nbsp;\n\u003cimg src=\"https://img.shields.io/badge/macOS-000000?style=flat\u0026logo=apple\u0026logoColor=white\" width=\"48\" height=\"24\"\u003e\u0026nbsp;\n\u003cimg src=\"https://img.shields.io/badge/Windows-0078D6?style=flat\u0026logo=windows\u0026logoColor=white\" width=\"48\" height=\"24\"\u003e\u0026nbsp;\n\n## A bit of history, a bit of theory\n\nMailboxes are one of the fundamental parts of the [actor model originated in **1973**](https://en.wikipedia.org/wiki/Actor_model): \n\u003e An actor is an object that carries out its actions in response to communications it receives.\n\u003e Through the mailbox mechanism, actors can decouple the reception of a message from its elaboration.\n\u003e A mailbox is nothing more than the data structure (FIFO) that holds messages.\n\nI first encountered MailBox in the late 80s while working on a real-time system: \n\u003e \"A **mailbox** is object that can be used for inter-task\ncommunication. When task A wants to send an object to task B, task A\nmust send the object to the mailbox, and task B must visit the mailbox,\nwhere, if an object isn't there, it has the option of *waiting for any\ndesired length of time*...\" \n\u003e **iRMX 86™ NUCLEUS REFERENCE MANUAL** _Copyright @ 1980, 1981 Intel Corporation.\n\nSince than I have used it in:\n\n|     OS      | Language(s) |\n|:-----------:|:-----------:|\n|    iRMX     |  *PL/M-86*  |\n|     AIX     |     *C*     |\n|   Windows   |  *C++/C#*   |\n|    Linux    |    *Go*     |\n\n**Now it's Zig time!!!**\n\n## Why?\nIf your thread runs in \"Fire and Forget\" mode, you don't need Mailbox.\n \nBut in real multithreaded applications, threads communicate with each other as\nmembers of a work team.\n\n**Mailbox** provides a convenient and simple inter-thread communication:\n- thread safe\n- asynchronous\n- non-blocking \n- cancelable\n- no own allocations\n- unbounded\n- fan-out/fan-in\n  \n\n## Example of usage - 'Echo' \n```zig\n    // Mbx is Mailbox with usize letter(data)\n    const Mbx = mailbox.MailBox(usize);\n\n    // Echo - runs on own thread\n    // It has two mailboxes\n    // \"TO\" and \"FROM\" - from the client point of the view\n    // Receives letter via 'TO' mailbox\n    // Replies letter without change (echo) to \"FROM\" mailbox\n    const Echo = struct {\n        const Self = @This();\n\n        to: Mbx = undefined,\n        from: Mbx = undefined,\n        thread: Thread = undefined,\n\n        // Mailboxes creation and start of the thread\n        // Pay attention, that client code does not use\n        // any thread \"API\" - all embedded within Echo\n        pub fn start(echo: *Self) void {\n            echo.to = .{};\n            echo.from = .{};\n            echo.thread = std.Thread.spawn(.{}, run, .{echo}) catch unreachable;\n        }\n\n        // Echo thread function\n        fn run(echo: *Self) void {\n            // Main loop:\n            while (true) {\n                // Receive - exit from the thread if mailbox was closed\n                const envelope = echo.to.receive(100000000) catch break;\n                // Reply to the client\n                // Exit from the thread if mailbox was closed\n                _ = echo.from.send(envelope) catch break;\n            }\n        }\n\n        // Wait exit from the thread\n        pub fn waitFinish(echo: *Self) void {\n            echo.thread.join();\n        }\n\n        // Close mailboxes\n        // As result Echo should stop processing\n        // and exit from the thread.\n        pub fn stop(echo: *Self) !void {\n            _ = echo.to.close();\n            _ = echo.from.close();\n        }\n    };\n\n    var echo = try std.testing.allocator.create(Echo);\n\n    // Start Echo(on own thread)\n    echo.start();\n    defer echo.stop();\n\n    defer {\n        // Wait finish of Echo\n        echo.waitFinish();\n        std.testing.allocator.destroy(echo);\n    }\n\n    // because nothing was send to 'TO' mailbox, nothing should be received\n    // from 'FROM' mailbox\n    try testing.expectError(error.Timeout, echo.from.receive(100));\n\n    // Create wrapper for the data\n    const envl = try std.testing.allocator.create(Mbx.Envelope);\n    defer std.testing.allocator.destroy(envl);\n\n    // Send/Receive loop\n    for (0..6) |indx| {\n        // Set value for send [0-5]\n        envl.letter = indx;\n\n        // Send to 'TO' mailbox\n        try echo.to.send(envl);\n\n        // Wait received data from OUT mailbox\n        const back = echo.from.receive(1000000);\n\n        if (back) |val| {\n            // Expected value == index [0-5]\n            try testing.expect(val.letter == indx);\n        } else |_| {\n            try testing.expect(false);\n        }\n    }\n```\n\n## Boring details\n\nMailbox of *[]const u8* 'Letters':\n```zig\nconst Rumors = mailbox.MailBox([]const u8);\nconst rmrsMbx : Rumors = .{};\n```\n\n**Envelope** is a wrapper of actual user defined type **Letter**.\n```zig\n        pub const Envelope = struct {\n            prev: ?*Envelope = null,\n            next: ?*Envelope = null,\n            letter: Letter,\n        };\n```\nIn fact Mailbox is a queue(FIFO) of Envelope(s).\n\nMailBox supports following operations:\n- send *Envelope* to MailBox (*enqueue*) and wakeup waiting receiver(s)\n- receive *Envelope* from Mailbox (*dequeue*) with time-out\n- close Mailbox:\n  - disables further operations\n  - first close returns List of non-processed *Envelope(s)* for free/reuse etc.\n\nFeel free to suggest improvements in doc and code.\n\n\n## License\n[MIT](LICENSE)\n\n## Installation\nYou finally got to installation!\n\n### Submodules\n\nCreate folder *'deps'* under *'src'* and mailbox submodule:  \n```bash\nmkdif src/deps        \ngit submodule add https://github.com/g41797/mailbox src/deps/mailbox\n```\nImport mailbox:\n```zig\nconst mailbox = @import(\"deps/mailbox/src/mailbox.zig\");\n```\nUse mailbox:\n```zig\nconst MsgBlock = struct {\n    len: usize = undefined,\n    buff: [1024]u8 = undefined,\n};\n\nconst Msgs = mailbox.MailBox(MsgBlock);\n\nvar msgs: Msgs = .{};\n...................\n_ = msgs.close();\n```\n\nPeriodically update submodule(s):\n```bash\ngit submodule update --remote\n```\n\n### Package Manager\n\nWith an existing Zig project, adding Mailbox to it is easy:\n\n1. Add mailbox to your `build.zig.zon`\n2. Add mailbox to your `build.zig`\n\nTo add mailbox to `build.zig.zon` simply run the following in your terminal:\n\n```sh\ncd my-example-project\nzig fetch --save=mailbox git+https://github.com/g41797/mailbox\n```\n\nand in your `build.zig.zon` you should find a new dependency like:\n\n```zig\n.{\n    .name = \"My example project\",\n    .version = \"0.0.1\",\n\n    .dependencies = .{\n        .mailbox = .{\n            .url = \"git+https://github.com/g41797/mailbox#3f794f34f5d859e7090c608da998f3b8856f8329\",\n            .hash = \"122068e7811ec1bfc2a81c9250078dd5dafa9dca4eb3f1910191ba060585526f03fe\",\n        },\n    },\n    .paths = .{\n        \"\",\n    },\n}\n```\n\nThen, in your `build.zig`'s `build` function, add the following before\n`b.installArtifact(exe)`:\n\n```zig\n    const mailbox = b.dependency(\"mailbox\", .{\n        .target = target,\n        .optimize = optimize,\n    });\n\n    exe.root_module.addImport(\"mailbox\", mailbox.module(\"mailbox\"));\n```\n\nFrom then on, you can use the Mailbox package in your project.\n\n## Last warning\nFirst rule of multithreading:\n\u003e**If you can do without multithreading - do without.**\n\u003cbr\u003e    \n\n*Powered by*  [![clion](_logo/CLion_icon.png)][refclion]\n\n[refclion]: https://www.jetbrains.com/clion/\n\n\n","funding_links":[],"categories":["Zig","Systems Programming"],"sub_categories":["Multithreading"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fg41797%2Fmailbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fg41797%2Fmailbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fg41797%2Fmailbox/lists"}