3 releases (breaking)
0.3.2 | Mar 20, 2024 |
---|---|
0.3.1 |
|
0.3.0 |
|
0.2.0 | Feb 14, 2022 |
0.1.0 | Feb 10, 2022 |
#152 in Asynchronous
1,740 downloads per month
Used in asynchronix
53KB
678 lines
multishot
An async, lock-free, reusable channel for sending single values to asynchronous tasks.
Overview
In a multi-shot channel, the receiver half is reusable and able to recycle the sender half without ever re-allocating. Sending or awaiting a value and recycling the sender are all lock-free operations, the last two being additionally wait-free. Producing a new sender does not require additional synchronization or spinning: it is guaranteed to succeed immediately if the value sent by a previous sender was received.
Usage
Add this to your Cargo.toml
:
[dependencies]
multishot = "0.3.2"
Example
use std::thread;
async {
let (s, mut r) = multishot::channel();
// Send a value to the channel from another thread.
thread::spawn(move || {
s.send("42");
});
// Receive the value.
let res = r.recv().await;
assert_eq!(res, Ok("42"));
// Recycle the sender. This is guaranteed to succeed if the previous
// message has been read.
let s = r.sender().unwrap();
// Drop the sender on another thread without sending a message.
thread::spawn(move || {
drop(s);
});
// Receive an error.
let res = r.recv().await;
assert_eq!(res, Err(multishot::RecvError {}));
};
Safety
This is a low-level primitive and as such its implementation relies on unsafe
.
The test suite makes extensive use of Loom and MIRI to assess its correctness.
As amazing as they are, however, Loom and MIRI cannot formally prove the absence
of data races so soundness issues are possible.
Implementation
Sending, receiving and recycling a sender are lock-free operations; the last two are additionally wait-free.
Polling requires no read-modify-write (RMW) operation if the value is readily
available, 1 RMW if this is the first waker update and 2 RMWs otherwise. Sending
needs 1 RMW if no waker was registered, and typically 2 RMW if one was
registered. Compared to a non-reusable one-shot channel such as Tokio's, the
only extra cost is 1 RMW in case the waker was updated (which is rare in
practice). Also, the implementation of multishot
partially offsets this extra
cost by using arithmetic atomic operations when sending rather than the
typically more expensive compare-and-swap operation.
License
This software is licensed under the Apache License, Version 2.0 or the MIT license, at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
Dependencies
~0–26MB
~330K SLoC