- Notifications
You must be signed in to change notification settings - Fork3
Zig Mailbox is convenient inter-thread communication mechanizm.
License
g41797/mailbox
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Mailboxes are one of the fundamental parts of theactor model originated in1973:
An actor is an object that carries out its actions in response to communications it receives.Through the mailbox mechanism, actors can decouple the reception of a message from its elaboration.A mailbox is nothing more than the data structure (FIFO) that holds messages.
I first encountered MailBox in the late 80s while working on a real-time system:
"Amailbox is object that can be used for inter-taskcommunication. When task A wants to send an object to task B, task Amust send the object to the mailbox, and task B must visit the mailbox,where, if an object isn't there, it has the option ofwaiting for anydesired length of time..."iRMX 86™ NUCLEUS REFERENCE MANUAL _Copyright @ 1980, 1981 Intel Corporation.
Since than I have used it in:
OS | Language(s) |
---|---|
iRMX | PL/M-86 |
AIX | C |
Windows | C++/C# |
Linux | Go |
Now it's Zig time!!!
If your thread runs in "Fire and Forget" mode, you don't need Mailbox.
But in real multithreaded applications, threads communicate with each other asmembers of a work team.
Mailbox provides a convenient and simple inter-thread communication:
- thread safe
- asynchronous
- cancelable
- no own allocations
- unbounded
- fan-out/fan-in
// Mbx is Mailbox with usize letter(data)constMbx=mailbox.MailBox(usize);// Echo - runs on own thread// It has two mailboxes// "TO" and "FROM" - from the client point of the view// Receives letter via 'TO' mailbox// Replies letter without change (echo) to "FROM" mailboxconstEcho=struct {constSelf=@This();to:Mbx=undefined,from:Mbx=undefined,thread:Thread=undefined,// Mailboxes creation and start of the thread// Pay attention, that client code does not use// any thread "API" - all embedded within Echopubfnstart(echo:*Self)void {echo.to= .{};echo.from= .{};echo.thread=std.Thread.spawn(.{},run, .{echo})catchunreachable; }// Echo thread functionfnrun(echo:*Self)void {// Main loop:while (true) {// Receive - exit from the thread if mailbox was closedconstenvelope=echo.to.receive(100000000)catchbreak;// Reply to the client// Exit from the thread if mailbox was closed_=echo.from.send(envelope)catchbreak; } }// Wait exit from the threadpubfnwaitFinish(echo:*Self)void {echo.thread.join(); }// Close mailboxes// As result Echo should stop processing// and exit from the thread.pubfnstop(echo:*Self)!void {_=echo.to.close();_=echo.from.close(); } };varecho=trystd.testing.allocator.create(Echo);// Start Echo(on own thread)echo.start();deferecho.stop();defer {// Wait finish of Echoecho.waitFinish();std.testing.allocator.destroy(echo); }// because nothing was send to 'TO' mailbox, nothing should be received// from 'FROM' mailboxtrytesting.expectError(error.Timeout,echo.from.receive(100));// Create wrapper for the dataconstenvl=trystd.testing.allocator.create(Mbx.Envelope);deferstd.testing.allocator.destroy(envl);// Send/Receive loopfor (0..6)|indx| {// Set value for send [0-5]envl.letter=indx;// Send to 'TO' mailboxtryecho.to.send(envl);// Wait received data from OUT mailboxconstback=echo.from.receive(1000000);if (back)|val| {// Expected value == index [0-5]trytesting.expect(val.letter==indx); }else|_| {trytesting.expect(false); } }
Mailbox of[]const u8 'Letters':
constRumors=mailbox.MailBox([]constu8);constrmrsMbx :Rumors= .{};
Envelope is a wrapper of actual user defined typeLetter.
pubconstEnvelope=struct {prev:?*Envelope=null,next:?*Envelope=null,letter:Letter, };
In fact Mailbox is a queue(FIFO) of Envelope(s).
MailBox supports following operations:
- sendEnvelope to MailBox (enqueue) and wakeup waiting receiver(s)
- receiveEnvelope from Mailbox (dequeue) with time-out
- interrupt - wake-up receiver thread
- close Mailbox:
- disables further operations
- first close returns List of non-processedEnvelope(s) for free/reuse etc.
In order to be intrusive, Envelope should looks like
pubconstT=struct {prev:?*T=null,next:?*T=null,additionalstuff };
Dumb example:
constMsgU32=struct {prev:?*MsgU32=null,next:?*MsgU32=null,stuff:u32=undefined, };
MailBoxIntrusive has exactly the same functionality as formerMailBox.
For curious:
I am usingMailBox in own projects:
You finally got to installation!
With an existing Zig project, adding Mailbox to it is easy:
- Add mailbox to your
build.zig.zon
- Add mailbox to your
build.zig
To add mailbox tobuild.zig.zon
simply run the following in your terminal:
cd my-example-projectzig fetch --save=mailbox git+https://github.com/g41797/mailbox
and in yourbuild.zig.zon
you should find a new dependency like:
.{ .name="My example project", .version="0.0.1", .dependencies= .{ .mailbox= .{ .url="git+https://github.com/g41797/mailbox#3f794f34f5d859e7090c608da998f3b8856f8329", .hash="122068e7811ec1bfc2a81c9250078dd5dafa9dca4eb3f1910191ba060585526f03fe", }, }, .paths= .{"", },}
Then, in yourbuild.zig
'sbuild
function, add the following beforeb.installArtifact(exe)
:
constmailbox=b.dependency("mailbox", .{ .target=target, .optimize=optimize, });exe.root_module.addImport("mailbox",mailbox.module("mailbox"));
From then on, you can use the Mailbox package in your project.
Seebuild.zig of the real project
First rule of multithreading:
If you can do without multithreading - do without.
About
Zig Mailbox is convenient inter-thread communication mechanizm.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.
Contributors3
Uh oh!
There was an error while loading.Please reload this page.