An async, lock-free, reusable channel for sending single values to asynchronous tasks.
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.
Add this to your Cargo.toml
:
toml
[dependencies]
multishot = "0.1.0"
```rust 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 {}));
}; ```
This is a low-level primitive and as such its implementation relies on unsafe
.
The test suite makes extensive use of [Loom] to assess its correctness. As
amazing as it is, however, Loom is only a tool: it cannot formally prove the
absence of data races.
The implementation uses only 2 read-modify-write operations to poll the receiver's future (or none if the value is already present) and typically 1 or 2 read-modify-write for sending, depending whether a waker was registered or not. Overall, compared to a non-reusable one-shot channel such as Tokio's, the only extra cost is 1 read-modify-write operation if and only if a waker was already registered when the value is sent. The implementation of Multishot partially offsets this small extra cost, however, by using arithmetic atomic operations when sending a value rather than typically more expensive compare-and-swap operations.
This software is licensed under the Apache License, Version 2.0 or the MIT license, at your option.
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.