357 KiB
Crate Documentation
Version: 1.48.0
Format Version: 56
Module tokio
A runtime for writing reliable network applications without compromising speed.
Tokio is an event-driven, non-blocking I/O platform for writing asynchronous applications with the Rust programming language. At a high level, it provides a few major components:
- Tools for working with asynchronous tasks, including synchronization primitives and channels and timeouts, sleeps, and intervals.
- APIs for performing asynchronous I/O, including TCP and UDP sockets, filesystem operations, and process and signal management.
- A runtime for executing asynchronous code, including a task scheduler,
an I/O driver backed by the operating system's event queue (
epoll,kqueue,IOCP, etc...), and a high performance timer.
Guide level documentation is found on the website.
A Tour of Tokio
Tokio consists of a number of modules that provide a range of functionality essential for implementing asynchronous applications in Rust. In this section, we will take a brief tour of Tokio, summarizing the major APIs and their uses.
The easiest way to get started is to enable all features. Do this by
enabling the full feature flag:
tokio = { version = "1", features = ["full"] }
Authoring applications
Tokio is great for writing applications and most users in this case shouldn't
worry too much about what features they should pick. If you're unsure, we suggest
going with full to ensure that you don't run into any road blocks while you're
building your application.
Example
This example shows the quickest way to get started with Tokio.
tokio = { version = "1", features = ["full"] }
Authoring libraries
As a library author your goal should be to provide the lightest weight crate that is based on Tokio. To achieve this you should ensure that you only enable the features you need. This allows users to pick up your crate without having to enable unnecessary features.
Example
This example shows how you may want to import features for a library that just
needs to tokio::spawn and use a TcpStream.
tokio = { version = "1", features = ["rt", "net"] }
Working With Tasks
Asynchronous programs in Rust are based around lightweight, non-blocking
units of execution called tasks. The tokio::task module provides
important tools for working with tasks:
- The
spawnfunction andJoinHandletype, for scheduling a new task on the Tokio runtime and awaiting the output of a spawned task, respectively, - Functions for running blocking operations in an asynchronous task context.
The tokio::task module is present only when the "rt" feature flag
is enabled.
The tokio::sync module contains synchronization primitives to use when
needing to communicate or share data. These include:
- channels (
oneshot,mpsc,watch, andbroadcast), for sending values between tasks, - a non-blocking
Mutex, for controlling access to a shared, mutable value, - an asynchronous
Barriertype, for multiple tasks to synchronize before beginning a computation.
The tokio::sync module is present only when the "sync" feature flag is
enabled.
The tokio::time module provides utilities for tracking time and
scheduling work. This includes functions for setting timeouts for
tasks, sleeping work to run in the future, or repeating an operation at an
interval.
In order to use tokio::time, the "time" feature flag must be enabled.
Finally, Tokio provides a runtime for executing asynchronous tasks. Most
applications can use the #[tokio::main] macro to run their code on the
Tokio runtime. However, this macro provides only basic configuration options. As
an alternative, the tokio::runtime module provides more powerful APIs for configuring
and managing runtimes. You should use that module if the #[tokio::main] macro doesn't
provide the functionality you need.
Using the runtime requires the "rt" or "rt-multi-thread" feature flags, to
enable the current-thread single-threaded scheduler and the multi-thread
scheduler, respectively. See the runtime module
documentation for details. In addition, the "macros" feature
flag enables the #[tokio::main] and #[tokio::test] attributes.
CPU-bound tasks and blocking code
Tokio is able to concurrently run many tasks on a few threads by repeatedly
swapping the currently running task on each thread. However, this kind of
swapping can only happen at .await points, so code that spends a long time
without reaching an .await will prevent other tasks from running. To
combat this, Tokio provides two kinds of threads: Core threads and blocking threads.
The core threads are where all asynchronous code runs, and Tokio will by default
spawn one for each CPU core. You can use the environment variable TOKIO_WORKER_THREADS
to override the default value.
The blocking threads are spawned on demand, can be used to run blocking code
that would otherwise block other tasks from running and are kept alive when
not used for a certain amount of time which can be configured with thread_keep_alive.
Since it is not possible for Tokio to swap out blocking tasks, like it
can do with asynchronous code, the upper limit on the number of blocking
threads is very large. These limits can be configured on the Builder.
To spawn a blocking task, you should use the spawn_blocking function.
# #[cfg(not(target_family = "wasm"))]
# {
#[tokio::main]
async fn main() {
// This is running on a core thread.
let blocking_task = tokio::task::spawn_blocking(|| {
// This is running on a blocking thread.
// Blocking here is ok.
});
// We can wait for the blocking task like this:
// If the blocking task panics, the unwrap below will propagate the
// panic.
blocking_task.await.unwrap();
}
# }
If your code is CPU-bound and you wish to limit the number of threads used to run it, you should use a separate thread pool dedicated to CPU bound tasks. For example, you could consider using the rayon library for CPU-bound tasks. It is also possible to create an extra Tokio runtime dedicated to CPU-bound tasks, but if you do this, you should be careful that the extra runtime runs only CPU-bound tasks, as IO-bound tasks on that runtime will behave poorly.
Hint: If using rayon, you can use a oneshot channel to send the result back
to Tokio when the rayon task finishes.
Asynchronous IO
As well as scheduling and running tasks, Tokio provides everything you need to perform input and output asynchronously.
The tokio::io module provides Tokio's asynchronous core I/O primitives,
the AsyncRead, AsyncWrite, and AsyncBufRead traits. In addition,
when the "io-util" feature flag is enabled, it also provides combinators and
functions for working with these traits, forming as an asynchronous
counterpart to std::io.
Tokio also includes APIs for performing various kinds of I/O and interacting with the operating system asynchronously. These include:
tokio::net, which contains non-blocking versions of TCP, UDP, and Unix Domain Sockets (enabled by the "net" feature flag),tokio::fs, similar tostd::fsbut for performing filesystem I/O asynchronously (enabled by the "fs" feature flag),tokio::signal, for asynchronously handling Unix and Windows OS signals (enabled by the "signal" feature flag),tokio::process, for spawning and managing child processes (enabled by the "process" feature flag).
Examples
A simple TCP echo server:
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
// In a loop, read data from the socket and write the data back.
loop {
let n = match socket.read(&mut buf).await {
// socket closed
Ok(0) => return,
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from socket; err = {:?}", e);
return;
}
};
// Write the data back
if let Err(e) = socket.write_all(&buf[0..n]).await {
eprintln!("failed to write to socket; err = {:?}", e);
return;
}
}
});
}
}
# }
Feature flags
Tokio uses a set of feature flags to reduce the amount of compiled code. It
is possible to just enable certain features over others. By default, Tokio
does not enable any features but allows one to enable a subset for their use
case. Below is a list of the available feature flags. You may also notice
above each function, struct and trait there is listed one or more feature flags
that are required for that item to be used. If you are new to Tokio it is
recommended that you use the full feature flag which will enable all public APIs.
Beware though that this will pull in many extra dependencies that you may not
need.
full: Enables all features listed below excepttest-utilandtracing.rt: Enablestokio::spawn, the current-thread scheduler, and non-scheduler utilities.rt-multi-thread: Enables the heavier, multi-threaded, work-stealing scheduler.io-util: Enables the IO basedExttraits.io-std: EnableStdout,StdinandStderrtypes.net: Enablestokio::nettypes such asTcpStream,UnixStreamandUdpSocket, as well as (on Unix-like systems)AsyncFdand (on FreeBSD)PollAio.time: Enablestokio::timetypes and allows the schedulers to enable the built in timer.process: Enablestokio::processtypes.macros: Enables#[tokio::main]and#[tokio::test]macros.sync: Enables alltokio::synctypes.signal: Enables alltokio::signaltypes.fs: Enablestokio::fstypes.test-util: Enables testing based infrastructure for the Tokio runtime.parking_lot: As a potential optimization, use the [parking_lot] crate's synchronization primitives internally. Also, this dependency is necessary to construct some of our primitives in aconstcontext.MSRVmay increase according to the [parking_lot] release in use.
Note: AsyncRead and AsyncWrite traits do not require any features and are
always available.
Unstable features
Some feature flags are only available when specifying the tokio_unstable flag:
tracing: Enables tracing events.
Likewise, some parts of the API are only available with the same flag:
task::Builder- Some methods on [
task::JoinSet] - [
runtime::RuntimeMetrics] - [
runtime::Builder::on_task_spawn] - [
runtime::Builder::on_task_terminate] - [
runtime::Builder::unhandled_panic] - [
runtime::TaskMeta]
This flag enables unstable features. The public API of these features
may break in 1.x releases. To enable these features, the --cfg tokio_unstable argument must be passed to rustc when compiling. This
serves to explicitly opt-in to features which may break semver conventions,
since Cargo does not yet directly support such opt-ins.
You can specify it in your project's .cargo/config.toml file:
[build]
rustflags = ["--cfg", "tokio_unstable"]
[build] section does not go in a
Cargo.toml file. Instead it must be placed in the Cargo config
file .cargo/config.toml.
Alternatively, you can specify it with an environment variable:
## Many *nix shells:
export RUSTFLAGS="--cfg tokio_unstable"
cargo build
## Windows PowerShell:
$Env:RUSTFLAGS="--cfg tokio_unstable"
cargo build
Supported platforms
Tokio currently guarantees support for the following platforms:
- Linux
- Windows
- Android (API level 21)
- macOS
- iOS
- FreeBSD
Tokio will continue to support these platforms in the future. However, future releases may change requirements such as the minimum required libc version on Linux, the API level on Android, or the supported FreeBSD release.
Beyond the above platforms, Tokio is intended to work on all platforms supported by the mio crate. You can find a longer list in mio's documentation. However, these additional platforms may become unsupported in the future.
Note that Wine is considered to be a different platform from Windows. See mio's documentation for more information on Wine support.
WASM support
Tokio has some limited support for the WASM platform. Without the
tokio_unstable flag, the following features are supported:
syncmacrosio-utilrttime
Enabling any other feature (including full) will cause a compilation
failure.
The time module will only work on WASM platforms that have support for
timers (e.g. wasm32-wasi). The timing functions will panic if used on a WASM
platform that does not support timers.
Note also that if the runtime becomes indefinitely idle, it will panic immediately instead of blocking forever. On platforms that don't support time, this means that the runtime can never be idle in any way.
Unstable WASM support
Tokio also has unstable support for some additional WASM features. This
requires the use of the tokio_unstable flag.
Using this flag enables the use of tokio::net on the wasm32-wasi target.
However, not all methods are available on the networking types as WASI
currently does not support the creation of new sockets from within WASM.
Because of this, sockets must currently be created via the FromRawFd
trait.
Modules
Module fs
Attributes:
Other("#[<cfg>(feature = \"fs\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"fs\")))]")Other("#[doc(cfg(feature = \"fs\"))]")Other("#[<cfg>(not(loom))]")
Asynchronous file utilities.
This module contains utility methods for working with the file system asynchronously. This includes reading/writing to files, and working with directories.
Be aware that most operating systems do not provide asynchronous file system
APIs. Because of that, Tokio will use ordinary blocking file operations
behind the scenes. This is done using the spawn_blocking threadpool to
run them in the background.
The tokio::fs module should only be used for ordinary files. Trying to use
it with e.g., a named pipe on Linux can result in surprising behavior,
such as hangs during runtime shutdown. For special files, you should use a
dedicated type such as tokio::net::unix::pipe or AsyncFd instead.
Currently, Tokio will always use spawn_blocking on all platforms, but it
may be changed to use asynchronous file system APIs such as io_uring in the
future.
Usage
The easiest way to use this module is to use the utility functions that operate on entire files:
The two read functions reads the entire file and returns its contents.
The write function takes the contents of the file and writes those
contents to the file. It overwrites the existing file, if any.
For example, to read the file:
# async fn dox() -> std::io::Result<()> {
let contents = tokio::fs::read_to_string("my_file.txt").await?;
println!("File has {} lines.", contents.lines().count());
# Ok(())
# }
To overwrite the file:
# async fn dox() -> std::io::Result<()> {
let contents = "First line.\nSecond line.\nThird line.\n";
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
# Ok(())
# }
Using File
The main type for interacting with files is File. It can be used to read
from and write to a given file. This is done using the AsyncRead and
AsyncWrite traits. This type is generally used when you want to do
something more complex than just reading or writing the entire contents in
one go.
Note: It is important to use flush when writing to a Tokio
File. This is because calls to write will return before the write has
finished, and flush will wait for the write to finish. (The write will
happen even if you don't flush; it will just happen later.) This is
different from std::fs::File, and is due to the fact that File uses
spawn_blocking behind the scenes.
For example, to count the number of lines in a file without loading the entire file into memory:
use tokio::fs::File;
use tokio::io::AsyncReadExt;
# async fn dox() -> std::io::Result<()> {
let mut file = File::open("my_file.txt").await?;
let mut chunk = vec![0; 4096];
let mut number_of_lines = 0;
loop {
let len = file.read(&mut chunk).await?;
if len == 0 {
// Length of zero means end of file.
break;
}
for &b in &chunk[..len] {
if b == b'\n' {
number_of_lines += 1;
}
}
}
println!("File has {} lines.", number_of_lines);
# Ok(())
# }
For example, to write a file line-by-line:
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
# async fn dox() -> std::io::Result<()> {
let mut file = File::create("my_file.txt").await?;
file.write_all(b"First line.\n").await?;
file.write_all(b"Second line.\n").await?;
file.write_all(b"Third line.\n").await?;
// Remember to call `flush` after writing!
file.flush().await?;
# Ok(())
# }
Tuning your file IO
Tokio's file uses spawn_blocking behind the scenes, and this has serious
performance consequences. To get good performance with file IO on Tokio, it
is recommended to batch your operations into as few spawn_blocking calls
as possible.
One example of this difference can be seen by comparing the two reading
examples above. The first example uses tokio::fs::read, which reads the
entire file in a single spawn_blocking call, and then returns it. The
second example will read the file in chunks using many spawn_blocking
calls. This means that the second example will most likely be more expensive
for large files. (Of course, using chunks may be necessary for very large
files that don't fit in memory.)
The following examples will show some strategies for this:
When creating a file, write the data to a String or Vec<u8> and then
write the entire file in a single spawn_blocking call with
tokio::fs::write.
# async fn dox() -> std::io::Result<()> {
let mut contents = String::new();
contents.push_str("First line.\n");
contents.push_str("Second line.\n");
contents.push_str("Third line.\n");
tokio::fs::write("my_file.txt", contents.as_bytes()).await?;
# Ok(())
# }
Use BufReader and BufWriter to buffer many small reads or writes
into a few large ones. This example will most likely only perform one
spawn_blocking call.
use tokio::fs::File;
use tokio::io::{AsyncWriteExt, BufWriter};
# async fn dox() -> std::io::Result<()> {
let mut file = BufWriter::new(File::create("my_file.txt").await?);
file.write_all(b"First line.\n").await?;
file.write_all(b"Second line.\n").await?;
file.write_all(b"Third line.\n").await?;
// Due to the BufWriter, the actual write and spawn_blocking
// call happens when you flush.
file.flush().await?;
# Ok(())
# }
Manually use std::fs inside spawn_blocking.
use std::fs::File;
use std::io::{self, Write};
use tokio::task::spawn_blocking;
# async fn dox() -> std::io::Result<()> {
spawn_blocking(move || {
let mut file = File::create("my_file.txt")?;
file.write_all(b"First line.\n")?;
file.write_all(b"Second line.\n")?;
file.write_all(b"Third line.\n")?;
// Unlike Tokio's file, the std::fs file does
// not need flush.
io::Result::Ok(())
}).await.unwrap()?;
# Ok(())
# }
It's also good to be aware of [File::set_max_buf_size], which controls the
maximum amount of bytes that Tokio's File will read or write in a single
spawn_blocking call. The default is two megabytes, but this is subject
to change.
pub mod fs { /* ... */ }
Re-exports
Re-export canonicalize
pub use self::canonicalize::canonicalize;
Re-export create_dir
pub use self::create_dir::create_dir;
Re-export create_dir_all
pub use self::create_dir_all::create_dir_all;
Re-export DirBuilder
pub use self::dir_builder::DirBuilder;
Re-export File
pub use self::file::File;
Re-export hard_link
pub use self::hard_link::hard_link;
Re-export metadata
pub use self::metadata::metadata;
Re-export OpenOptions
pub use self::open_options::OpenOptions;
Re-export read
pub use self::read::read;
Re-export read_dir
pub use self::read_dir::read_dir;
Re-export DirEntry
pub use self::read_dir::DirEntry;
Re-export ReadDir
pub use self::read_dir::ReadDir;
Re-export read_link
pub use self::read_link::read_link;
Re-export read_to_string
pub use self::read_to_string::read_to_string;
Re-export remove_dir
pub use self::remove_dir::remove_dir;
Re-export remove_dir_all
pub use self::remove_dir_all::remove_dir_all;
Re-export remove_file
pub use self::remove_file::remove_file;
Re-export rename
pub use self::rename::rename;
Re-export set_permissions
pub use self::set_permissions::set_permissions;
Re-export symlink_metadata
pub use self::symlink_metadata::symlink_metadata;
Re-export write
pub use self::write::write;
Re-export copy
pub use self::copy::copy;
Re-export try_exists
pub use self::try_exists::try_exists;
Re-export symlink
Attributes:
Other("#[<cfg>(unix)]")Other("#[<cfg_attr>(docsrs, doc(cfg(unix)))]")Other("#[doc(cfg(unix))]")
pub use self::symlink::symlink;
Re-export symlink_dir
Attributes:
Other("#[<cfg>(any(all(doc, docsrs), windows))]")Other("#[<cfg_attr>(docsrs, doc(cfg(windows)))]")Other("#[doc(cfg(windows))]")
pub use self::symlink_dir::symlink_dir;
Re-export symlink_file
Attributes:
Other("#[<cfg>(any(all(doc, docsrs), windows))]")Other("#[<cfg_attr>(docsrs, doc(cfg(windows)))]")Other("#[doc(cfg(windows))]")
pub use self::symlink_file::symlink_file;
Module io
Attributes:
Other("#[<cfg_attr>(not(all(feature = \"rt\", feature = \"net\")),\nallow(dead_code, unused_imports))]")
Traits, helpers, and type definitions for asynchronous I/O functionality.
This module is the asynchronous version of std::io. Primarily, it
defines two traits, AsyncRead and AsyncWrite, which are asynchronous
versions of the Read and Write traits in the standard library.
AsyncRead and AsyncWrite
Like the standard library's Read and Write traits, AsyncRead and
AsyncWrite provide the most general interface for reading and writing
input and output. Unlike the standard library's traits, however, they are
asynchronous — meaning that reading from or writing to a tokio::io
type will yield to the Tokio scheduler when IO is not ready, rather than
blocking. This allows other tasks to run while waiting on IO.
Another difference is that AsyncRead and AsyncWrite only contain
core methods needed to provide asynchronous reading and writing
functionality. Instead, utility methods are defined in the AsyncReadExt
and AsyncWriteExt extension traits. These traits are automatically
implemented for all values that implement AsyncRead and AsyncWrite
respectively.
End users will rarely interact directly with AsyncRead and
AsyncWrite. Instead, they will use the async functions defined in the
extension traits. Library authors are expected to implement AsyncRead
and AsyncWrite in order to provide types that behave like byte streams.
Even with these differences, Tokio's AsyncRead and AsyncWrite traits
can be used in almost exactly the same manner as the standard library's
Read and Write. Most types in the standard library that implement Read
and Write have asynchronous equivalents in tokio that implement
AsyncRead and AsyncWrite, such as File and TcpStream.
For example, the standard library documentation introduces Read by
demonstrating reading some bytes from a std::fs::File. We
can do the same with tokio::fs::File:
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::io::{self, AsyncReadExt};
use tokio::fs::File;
#[tokio::main]
async fn main() -> io::Result<()> {
let mut f = File::open("foo.txt").await?;
let mut buffer = [0; 10];
// read up to 10 bytes
let n = f.read(&mut buffer).await?;
println!("The bytes: {:?}", &buffer[..n]);
Ok(())
}
# }
Buffered Readers and Writers
Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
making near-constant calls to the operating system. To help with this,
std::io comes with support for buffered readers and writers,
and therefore, tokio::io does as well.
Tokio provides an async version of the std::io::BufRead trait,
AsyncBufRead; and async BufReader and BufWriter structs, which
wrap readers and writers. These wrappers use a buffer, reducing the number
of calls and providing nicer methods for accessing exactly what you want.
For example, BufReader works with the AsyncBufRead trait to add
extra methods to any async reader:
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::io::{self, BufReader, AsyncBufReadExt};
use tokio::fs::File;
#[tokio::main]
async fn main() -> io::Result<()> {
let f = File::open("foo.txt").await?;
let mut reader = BufReader::new(f);
let mut buffer = String::new();
// read a line into buffer
reader.read_line(&mut buffer).await?;
println!("{}", buffer);
Ok(())
}
# }
BufWriter doesn't add any new ways of writing; it just buffers every call
to write. However, you must flush
BufWriter to ensure that any buffered data is written.
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::io::{self, BufWriter, AsyncWriteExt};
use tokio::fs::File;
#[tokio::main]
async fn main() -> io::Result<()> {
let f = File::create("foo.txt").await?;
{
let mut writer = BufWriter::new(f);
// Write a byte to the buffer.
writer.write(&[42u8]).await?;
// Flush the buffer before it goes out of scope.
writer.flush().await?;
} // Unless flushed or shut down, the contents of the buffer is discarded on drop.
Ok(())
}
# }
Implementing AsyncRead and AsyncWrite
Because they are traits, we can implement AsyncRead and AsyncWrite for
our own types, as well. Note that these traits must only be implemented for
non-blocking I/O types that integrate with the futures type system. In
other words, these types must never block the thread, and instead the
current task is notified when the I/O resource is ready.
Conversion to and from Stream/Sink
It is often convenient to encapsulate the reading and writing of bytes in a
Stream or Sink of data.
Tokio provides simple wrappers for converting AsyncRead to Stream
and vice-versa in the tokio-util crate, see ReaderStream and
StreamReader.
There are also utility traits that abstract the asynchronous buffering
necessary to write your own adaptors for encoding and decoding bytes to/from
your structured data, allowing to transform something that implements
AsyncRead/AsyncWrite into a Stream/Sink, see Decoder and
Encoder in the tokio-util::codec module.
Standard input and output
Tokio provides asynchronous APIs to standard input, output, and error.
These APIs are very similar to the ones provided by std, but they also
implement AsyncRead and AsyncWrite.
Note that the standard input / output APIs must be used from the context of the Tokio runtime, as they require Tokio-specific features to function. Calling these functions outside of a Tokio runtime will panic.
std re-exports
Additionally, Error, ErrorKind, Result, and SeekFrom are
re-exported from std::io for ease of use.
pub mod io { /* ... */ }
Modules
Module bsd
Attributes:
Other("#[<cfg>(all(any(docsrs, target_os = \"freebsd\"), feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(target_os = \"freebsd\", feature = \"net\"))))]")Other("#[doc(cfg(all(target_os = \"freebsd\", feature = \"net\")))]")
BSD-specific I/O types.
pub mod bsd { /* ... */ }
Re-exports
Re-export Aio
pub use poll_aio::Aio;
Re-export AioEvent
pub use poll_aio::AioEvent;
Re-export AioSource
pub use poll_aio::AioSource;
Module unix
Attributes:
Other("#[<cfg>(all(unix, feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")Other("#[doc(cfg(all(unix, feature = \"net\")))]")
Asynchronous IO structures specific to Unix-like operating systems.
pub mod unix { /* ... */ }
Re-exports
Re-export AsyncFd
pub use super::async_fd::AsyncFd;
Re-export AsyncFdTryNewError
pub use super::async_fd::AsyncFdTryNewError;
Re-export AsyncFdReadyGuard
pub use super::async_fd::AsyncFdReadyGuard;
Re-export AsyncFdReadyMutGuard
pub use super::async_fd::AsyncFdReadyMutGuard;
Re-export TryIoError
pub use super::async_fd::TryIoError;
Re-exports
Re-export AsyncBufRead
pub use self::async_buf_read::AsyncBufRead;
Re-export AsyncRead
pub use self::async_read::AsyncRead;
Re-export AsyncSeek
pub use self::async_seek::AsyncSeek;
Re-export AsyncWrite
pub use self::async_write::AsyncWrite;
Re-export ReadBuf
pub use self::read_buf::ReadBuf;
Re-export Error
Attributes:
Other("#[doc(no_inline)]")
pub use std::io::Error;
Re-export ErrorKind
Attributes:
Other("#[doc(no_inline)]")
pub use std::io::ErrorKind;
Re-export Result
Attributes:
Other("#[doc(no_inline)]")
pub use std::io::Result;
Re-export SeekFrom
Attributes:
Other("#[doc(no_inline)]")
pub use std::io::SeekFrom;
Re-export Interest
Attributes:
Other("#[<cfg>(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))]")Other("#[<cfg_attr>(docsrs,\ndoc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))))]")Other("#[doc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",))))]")
pub use interest::Interest;
Re-export Ready
Attributes:
Other("#[<cfg>(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))]")Other("#[<cfg_attr>(docsrs,\ndoc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",)))))]")Other("#[doc(cfg(any(feature = \"net\",\nall(tokio_unstable, feature = \"io-uring\", feature = \"rt\", feature = \"fs\",\ntarget_os = \"linux\",))))]")
pub use ready::Ready;
Re-export stderr
Attributes:
Other("#[<cfg>(feature = \"io-std\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")Other("#[doc(cfg(feature = \"io-std\"))]")
pub use stderr::stderr;
Re-export Stderr
Attributes:
Other("#[<cfg>(feature = \"io-std\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")Other("#[doc(cfg(feature = \"io-std\"))]")
pub use stderr::Stderr;
Re-export stdin
Attributes:
Other("#[<cfg>(feature = \"io-std\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")Other("#[doc(cfg(feature = \"io-std\"))]")
pub use stdin::stdin;
Re-export Stdin
Attributes:
Other("#[<cfg>(feature = \"io-std\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")Other("#[doc(cfg(feature = \"io-std\"))]")
pub use stdin::Stdin;
Re-export stdout
Attributes:
Other("#[<cfg>(feature = \"io-std\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")Other("#[doc(cfg(feature = \"io-std\"))]")
pub use stdout::stdout;
Re-export Stdout
Attributes:
Other("#[<cfg>(feature = \"io-std\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-std\")))]")Other("#[doc(cfg(feature = \"io-std\"))]")
pub use stdout::Stdout;
Re-export split
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use split::split;
Re-export ReadHalf
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use split::ReadHalf;
Re-export WriteHalf
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use split::WriteHalf;
Re-export join
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use join::join;
Re-export Join
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use join::Join;
Re-export copy
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::copy;
Re-export copy_bidirectional
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::copy_bidirectional;
Re-export copy_bidirectional_with_sizes
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::copy_bidirectional_with_sizes;
Re-export copy_buf
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::copy_buf;
Re-export duplex
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::duplex;
Re-export empty
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::empty;
Re-export repeat
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::repeat;
Re-export sink
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::sink;
Re-export simplex
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::simplex;
Re-export AsyncBufReadExt
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::AsyncBufReadExt;
Re-export AsyncReadExt
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::AsyncReadExt;
Re-export AsyncSeekExt
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::AsyncSeekExt;
Re-export AsyncWriteExt
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::AsyncWriteExt;
Re-export BufReader
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::BufReader;
Re-export BufStream
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::BufStream;
Re-export BufWriter
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::BufWriter;
Re-export Chain
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Chain;
Re-export DuplexStream
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::DuplexStream;
Re-export Empty
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Empty;
Re-export Lines
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Lines;
Re-export Repeat
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Repeat;
Re-export Sink
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Sink;
Re-export Split
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Split;
Re-export Take
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::Take;
Re-export SimplexStream
Attributes:
Other("#[<cfg>(feature = \"io-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"io-util\")))]")Other("#[doc(cfg(feature = \"io-util\"))]")
pub use util::SimplexStream;
Module net
Attributes:
Other("#[<cfg>(not(loom))]")
TCP/UDP/Unix bindings for tokio.
This module contains the TCP/UDP/Unix networking types, similar to the standard library, which can be used to implement networking protocols.
Organization
TcpListenerandTcpStreamprovide functionality for communication over TCPUdpSocketprovides functionality for communication over UDPUnixListenerandUnixStreamprovide functionality for communication over a Unix Domain Stream Socket (available on Unix only)UnixDatagramprovides functionality for communication over Unix Domain Datagram Socket (available on Unix only)tokio::net::unix::pipefor FIFO pipes (available on Unix only)tokio::net::windows::named_pipefor Named Pipes (available on Windows only)
For IO resources not available in tokio::net, you can use AsyncFd.
pub mod net { /* ... */ }
Modules
Module tcp
Attributes:
Other("#[<cfg>(feature = \"net\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")Other("#[doc(cfg(feature = \"net\"))]")
TCP utility types.
pub mod tcp { /* ... */ }
Re-exports
Re-export ReadHalf
pub use split::ReadHalf;
Re-export WriteHalf
pub use split::WriteHalf;
Re-export OwnedReadHalf
pub use split_owned::OwnedReadHalf;
Re-export OwnedWriteHalf
pub use split_owned::OwnedWriteHalf;
Re-export ReuniteError
pub use split_owned::ReuniteError;
Module unix
Attributes:
Other("#[<cfg>(all(unix, feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")Other("#[doc(cfg(all(unix, feature = \"net\")))]")
Unix specific network types.
pub mod unix { /* ... */ }
Modules
Module pipe
Unix pipe types.
pub mod pipe { /* ... */ }
Types
Struct OpenOptions
Options and flags which can be used to configure how a FIFO file is opened.
This builder allows configuring how to create a pipe end from a FIFO file.
Generally speaking, when using OpenOptions, you'll first call new,
then chain calls to methods to set each option, then call either
open_receiver or open_sender, passing the path of the FIFO file you
are trying to open. This will give you a [io::Result] with a pipe end
inside that you can further operate on.
Examples
Opening a pair of pipe ends from a FIFO file:
use tokio::net::unix::pipe;
# use std::error::Error;
const FIFO_NAME: &str = "path/to/a/fifo";
# async fn dox() -> Result<(), Box<dyn Error>> {
let rx = pipe::OpenOptions::new().open_receiver(FIFO_NAME)?;
let tx = pipe::OpenOptions::new().open_sender(FIFO_NAME)?;
# Ok(())
# }
Opening a Sender on Linux when you are sure the file is a FIFO:
use tokio::net::unix::pipe;
use nix::{unistd::mkfifo, sys::stat::Mode};
# use std::error::Error;
// Our program has exclusive access to this path.
const FIFO_NAME: &str = "path/to/a/new/fifo";
# async fn dox() -> Result<(), Box<dyn Error>> {
mkfifo(FIFO_NAME, Mode::S_IRWXU)?;
let tx = pipe::OpenOptions::new()
.read_write(true)
.unchecked(true)
.open_sender(FIFO_NAME)?;
# Ok(())
# }
pub struct OpenOptions {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new() -> OpenOptions { /* ... */ }Creates a blank new set of options ready for configuration.
-
pub fn read_write(self: &mut Self, value: bool) -> &mut Self { /* ... */ }Sets the option for read-write access.
-
pub fn unchecked(self: &mut Self, value: bool) -> &mut Self { /* ... */ }Sets the option to skip the check for FIFO file type.
-
pub fn open_receiver<P: AsRef<Path>>(self: &Self, path: P) -> io::Result<Receiver> { /* ... */ }Creates a
Receiverfrom a FIFO file with the options specified byself. -
pub fn open_sender<P: AsRef<Path>>(self: &Self, path: P) -> io::Result<Sender> { /* ... */ }Creates a
Senderfrom a FIFO file with the options specified byself.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> OpenOptions { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Default
-
fn default() -> OpenOptions { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Sender
Writing end of a Unix pipe.
It can be constructed from a FIFO file with [OpenOptions::open_sender].
Opening a named pipe for writing involves a few steps.
Call to [OpenOptions::open_sender] might fail with an error indicating
different things:
- [
io::ErrorKind::NotFound] - There is no file at the specified path. - [
io::ErrorKind::InvalidInput] - The file exists, but it is not a FIFO. ENXIO- The file is a FIFO, but no process has it open for reading. Sleep for a while and try again.- Other OS errors not specific to opening FIFO files.
Opening a Sender from a FIFO file should look like this:
use tokio::net::unix::pipe;
use tokio::time::{self, Duration};
const FIFO_NAME: &str = "path/to/a/fifo";
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
// Wait for a reader to open the file.
let tx = loop {
match pipe::OpenOptions::new().open_sender(FIFO_NAME) {
Ok(tx) => break tx,
Err(e) if e.raw_os_error() == Some(libc::ENXIO) => {},
Err(e) => return Err(e.into()),
}
time::sleep(Duration::from_millis(50)).await;
};
# Ok(())
# }
On Linux, it is possible to create a Sender without waiting in a sleeping
loop. This is done by opening a named pipe in read-write access mode with
OpenOptions::read_write. This way, a Sender can at the same time hold
both a writing end and a reading end, and the latter allows to open a FIFO
without ENXIO error since the pipe is open for reading as well.
Sender cannot be used to read from a pipe, so in practice the read access
is only used when a FIFO is opened. However, using a Sender in read-write
mode may lead to lost data, because written data will be dropped by the
system as soon as all pipe ends are closed. To avoid lost data you have to
make sure that a reading end has been opened before dropping a Sender.
Note that using read-write access mode with FIFO files is not defined by the POSIX standard and it is only guaranteed to work on Linux.
use tokio::io::AsyncWriteExt;
use tokio::net::unix::pipe;
const FIFO_NAME: &str = "path/to/a/fifo";
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
let mut tx = pipe::OpenOptions::new()
.read_write(true)
.open_sender(FIFO_NAME)?;
// Asynchronously write to the pipe before a reader.
tx.write_all(b"hello world").await?;
# Ok(())
# }
pub struct Sender {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn from_file(file: File) -> io::Result<Sender> { /* ... */ }Creates a new
Senderfrom aFile. -
pub fn from_owned_fd(owned_fd: OwnedFd) -> io::Result<Sender> { /* ... */ }Creates a new
Senderfrom an [OwnedFd]. -
pub fn from_file_unchecked(file: File) -> io::Result<Sender> { /* ... */ }Creates a new
Senderfrom aFilewithout checking pipe properties. -
pub fn from_owned_fd_unchecked(owned_fd: OwnedFd) -> io::Result<Sender> { /* ... */ }Creates a new
Senderfrom an [OwnedFd] without checking pipe properties. -
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }Waits for any of the requested ready states.
-
pub async fn writable(self: &Self) -> io::Result<()> { /* ... */ }Waits for the pipe to become writable.
-
pub fn poll_write_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }Polls for write readiness.
-
pub fn try_write(self: &Self, buf: &[u8]) -> io::Result<usize> { /* ... */ }Tries to write a buffer to the pipe, returning how many bytes were
-
pub fn try_write_vectored(self: &Self, buf: &[io::IoSlice<''_>]) -> io::Result<usize> { /* ... */ }Tries to write several buffers to the pipe, returning how many bytes
-
pub fn into_blocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Converts the pipe into an [
OwnedFd] in blocking mode. -
pub fn into_nonblocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Converts the pipe into an [
OwnedFd] in nonblocking mode.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsFd
-
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
-
-
AsRawFd
-
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
-
-
AsyncWrite
-
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ } -
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<io::Result<usize>> { /* ... */ } -
fn is_write_vectored(self: &Self) -> bool { /* ... */ } -
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ } -
fn poll_shutdown(self: Pin<&mut Self>, _: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncWriteExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Receiver
Reading end of a Unix pipe.
It can be constructed from a FIFO file with [OpenOptions::open_receiver].
Examples
Receiving messages from a named pipe in a loop:
use tokio::net::unix::pipe;
use tokio::io::{self, AsyncReadExt};
const FIFO_NAME: &str = "path/to/a/fifo";
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
let mut rx = pipe::OpenOptions::new().open_receiver(FIFO_NAME)?;
loop {
let mut msg = vec![0; 256];
match rx.read_exact(&mut msg).await {
Ok(_) => {
/* handle the message */
}
Err(e) if e.kind() == io::ErrorKind::UnexpectedEof => {
// Writing end has been closed, we should reopen the pipe.
rx = pipe::OpenOptions::new().open_receiver(FIFO_NAME)?;
}
Err(e) => return Err(e.into()),
}
}
# }
On Linux, you can use a Receiver in read-write access mode to implement
resilient reading from a named pipe. Unlike Receiver opened in read-only
mode, read from a pipe in read-write mode will not fail with UnexpectedEof
when the writing end is closed. This way, a Receiver can asynchronously
wait for the next writer to open the pipe.
You should not use functions waiting for EOF such as read_to_end with
a Receiver in read-write access mode, since it may wait forever.
Receiver in this mode also holds an open writing end, which prevents
receiving EOF.
To set the read-write access mode you can use OpenOptions::read_write.
Note that using read-write access mode with FIFO files is not defined by
the POSIX standard and it is only guaranteed to work on Linux.
use tokio::net::unix::pipe;
use tokio::io::AsyncReadExt;
# use std::error::Error;
const FIFO_NAME: &str = "path/to/a/fifo";
# async fn dox() -> Result<(), Box<dyn Error>> {
let mut rx = pipe::OpenOptions::new()
.read_write(true)
.open_receiver(FIFO_NAME)?;
loop {
let mut msg = vec![0; 256];
rx.read_exact(&mut msg).await?;
/* handle the message */
}
# }
pub struct Receiver {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn from_file(file: File) -> io::Result<Receiver> { /* ... */ }Creates a new
Receiverfrom aFile. -
pub fn from_owned_fd(owned_fd: OwnedFd) -> io::Result<Receiver> { /* ... */ }Creates a new
Receiverfrom an [OwnedFd]. -
pub fn from_file_unchecked(file: File) -> io::Result<Receiver> { /* ... */ }Creates a new
Receiverfrom aFilewithout checking pipe properties. -
pub fn from_owned_fd_unchecked(owned_fd: OwnedFd) -> io::Result<Receiver> { /* ... */ }Creates a new
Receiverfrom an [OwnedFd] without checking pipe properties. -
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }Waits for any of the requested ready states.
-
pub async fn readable(self: &Self) -> io::Result<()> { /* ... */ }Waits for the pipe to become readable.
-
pub fn poll_read_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }Polls for read readiness.
-
pub fn try_read(self: &Self, buf: &mut [u8]) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffer, returning how
-
pub fn try_read_vectored(self: &Self, bufs: &mut [io::IoSliceMut<''_>]) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffers, returning
-
pub fn try_read_buf<B: BufMut>(self: &Self, buf: &mut B) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffer, advancing the
-
pub fn into_blocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Converts the pipe into an [
OwnedFd] in blocking mode. -
pub fn into_nonblocking_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Converts the pipe into an [
OwnedFd] in nonblocking mode.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsFd
-
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
-
-
AsRawFd
-
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
-
-
AsyncRead
-
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncReadExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function pipe
Creates a new anonymous Unix pipe.
This function will open a new pipe and associate both pipe ends with the default event loop.
If you need to create a pipe for communication with a spawned process, you can
use Stdio::piped() instead.
Errors
If creating a pipe fails, this function will return with the related OS error.
Examples
Create a pipe and pass the writing end to a spawned process.
use tokio::net::unix::pipe;
use tokio::process::Command;
# use tokio::io::AsyncReadExt;
# use std::error::Error;
# async fn dox() -> Result<(), Box<dyn Error>> {
let (tx, mut rx) = pipe::pipe()?;
let mut buffer = String::new();
let status = Command::new("echo")
.arg("Hello, world!")
.stdout(tx.into_blocking_fd()?)
.status();
rx.read_to_string(&mut buffer).await?;
assert!(status.await?.success());
assert_eq!(buffer, "Hello, world!\n");
# Ok(())
# }
Panics
This function panics if it is not called from within a runtime with IO enabled.
The runtime is usually set implicitly when this function is called
from a future driven by a tokio runtime, otherwise runtime can be set
explicitly with Runtime::enter function.
pub fn pipe() -> io::Result<(Sender, Receiver)> { /* ... */ }
Types
Type Alias uid_t
Attributes:
Other("#[allow(non_camel_case_types)]")
A type representing user ID.
pub type uid_t = u32;
Type Alias gid_t
Attributes:
Other("#[allow(non_camel_case_types)]")
A type representing group ID.
pub type gid_t = u32;
Type Alias pid_t
Attributes:
Other("#[allow(non_camel_case_types)]")
A type representing process and process group IDs.
pub type pid_t = i32;
Re-exports
Re-export ReadHalf
pub use split::ReadHalf;
Re-export WriteHalf
pub use split::WriteHalf;
Re-export OwnedReadHalf
pub use split_owned::OwnedReadHalf;
Re-export OwnedWriteHalf
pub use split_owned::OwnedWriteHalf;
Re-export ReuniteError
pub use split_owned::ReuniteError;
Re-export SocketAddr
pub use socketaddr::SocketAddr;
Re-export UCred
pub use ucred::UCred;
Module windows
Attributes:
Other("#[<cfg>(all(any(all(doc, docsrs), windows), feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(windows, feature = \"net\"))))]")Other("#[doc(cfg(all(windows, feature = \"net\")))]")
Windows specific network types.
pub mod windows { /* ... */ }
Modules
Module named_pipe
Tokio support for Windows named pipes.
pub mod named_pipe { /* ... */ }
Types
Struct NamedPipeServer
A Windows named pipe server.
Accepting client connections involves creating a server with
[ServerOptions::create] and waiting for clients to connect using
[NamedPipeServer::connect].
To avoid having clients sporadically fail with
[std::io::ErrorKind::NotFound] when they connect to a server, we must
ensure that at least one server instance is available at all times. This
means that the typical listen loop for a server is a bit involved, because
we have to ensure that we never drop a server accidentally while a client
might connect.
So a correctly implemented server looks like this:
use std::io;
use tokio::net::windows::named_pipe::ServerOptions;
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-idiomatic-server";
# #[tokio::main] async fn main() -> std::io::Result<()> {
// The first server needs to be constructed early so that clients can
// be correctly connected. Otherwise calling .wait will cause the client to
// error.
//
// Here we also make use of `first_pipe_instance`, which will ensure that
// there are no other servers up and running already.
let mut server = ServerOptions::new()
.first_pipe_instance(true)
.create(PIPE_NAME)?;
// Spawn the server loop.
let server = tokio::spawn(async move {
loop {
// Wait for a client to connect.
server.connect().await?;
let connected_client = server;
// Construct the next server to be connected before sending the one
// we already have of onto a task. This ensures that the server
// isn't closed (after it's done in the task) before a new one is
// available. Otherwise the client might error with
// `io::ErrorKind::NotFound`.
server = ServerOptions::new().create(PIPE_NAME)?;
let client = tokio::spawn(async move {
/* use the connected client */
# Ok::<_, std::io::Error>(())
});
# if true { break } // needed for type inference to work
}
Ok::<_, io::Error>(())
});
/* do something else not server related here */
# Ok(()) }
pub struct NamedPipeServer {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub unsafe fn from_raw_handle(handle: RawHandle) -> io::Result<Self> { /* ... */ }Constructs a new named pipe server from the specified raw handle.
-
pub fn info(self: &Self) -> io::Result<PipeInfo> { /* ... */ }Retrieves information about the named pipe the server is associated
-
pub async fn connect(self: &Self) -> io::Result<()> { /* ... */ }Enables a named pipe server process to wait for a client process to
-
pub fn disconnect(self: &Self) -> io::Result<()> { /* ... */ }Disconnects the server end of a named pipe instance from a client
-
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }Waits for any of the requested ready states.
-
pub async fn readable(self: &Self) -> io::Result<()> { /* ... */ }Waits for the pipe to become readable.
-
pub fn poll_read_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }Polls for read readiness.
-
pub fn try_read(self: &Self, buf: &mut [u8]) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffer, returning how
-
pub fn try_read_vectored(self: &Self, bufs: &mut [io::IoSliceMut<''_>]) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffers, returning
-
pub fn try_read_buf<B: BufMut>(self: &Self, buf: &mut B) -> io::Result<usize> { /* ... */ }Tries to read data from the stream into the provided buffer, advancing the
-
pub async fn writable(self: &Self) -> io::Result<()> { /* ... */ }Waits for the pipe to become writable.
-
pub fn poll_write_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }Polls for write readiness.
-
pub fn try_write(self: &Self, buf: &[u8]) -> io::Result<usize> { /* ... */ }Tries to write a buffer to the pipe, returning how many bytes were
-
pub fn try_write_vectored(self: &Self, buf: &[io::IoSlice<''_>]) -> io::Result<usize> { /* ... */ }Tries to write several buffers to the pipe, returning how many bytes
-
pub fn try_io<R, /* synthetic */ impl FnOnce() -> io::Result<R>: FnOnce() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnOnce() -> io::Result<R>) -> io::Result<R> { /* ... */ }Tries to read or write from the pipe using a user-provided IO operation.
-
pub async fn async_io<R, /* synthetic */ impl FnMut() -> io::Result<R>: FnMut() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnMut() -> io::Result<R>) -> io::Result<R> { /* ... */ }Reads or writes from the pipe using a user-provided IO operation.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsHandle
-
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
-
-
AsRawHandle
-
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
-
-
AsyncRead
-
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncReadExt
-
AsyncWrite
-
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ } -
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<io::Result<usize>> { /* ... */ } -
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ } -
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncWriteExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct NamedPipeClient
A Windows named pipe client.
Constructed using [ClientOptions::open].
Connecting a client correctly involves a few steps. When connecting through
[ClientOptions::open], it might error indicating one of two things:
- [
std::io::ErrorKind::NotFound] - There is no server available. ERROR_PIPE_BUSY- There is a server available, but it is busy. Sleep for a while and try again.
So a correctly implemented client looks like this:
use std::time::Duration;
use tokio::net::windows::named_pipe::ClientOptions;
use tokio::time;
use windows_sys::Win32::Foundation::ERROR_PIPE_BUSY;
const PIPE_NAME: &str = r"\\.\pipe\named-pipe-idiomatic-client";
# #[tokio::main] async fn main() -> std::io::Result<()> {
let client = loop {
match ClientOptions::new().open(PIPE_NAME) {
Ok(client) => break client,
Err(e) if e.raw_os_error() == Some(ERROR_PIPE_BUSY as i32) => (),
Err(e) => return Err(e),
}
time::sleep(Duration::from_millis(50)).await;
};
/* use the connected client */
# Ok(()) }
pub struct NamedPipeClient {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub unsafe fn from_raw_handle(handle: RawHandle) -> io::Result<Self> { /* ... */ }Constructs a new named pipe client from the specified raw handle.
-
pub fn info(self: &Self) -> io::Result<PipeInfo> { /* ... */ }Retrieves information about the named pipe the client is associated
-
pub async fn ready(self: &Self, interest: Interest) -> io::Result<Ready> { /* ... */ }Waits for any of the requested ready states.
-
pub async fn readable(self: &Self) -> io::Result<()> { /* ... */ }Waits for the pipe to become readable.
-
pub fn poll_read_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }Polls for read readiness.
-
pub fn try_read(self: &Self, buf: &mut [u8]) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffer, returning how
-
pub fn try_read_vectored(self: &Self, bufs: &mut [io::IoSliceMut<''_>]) -> io::Result<usize> { /* ... */ }Tries to read data from the pipe into the provided buffers, returning
-
pub fn try_read_buf<B: BufMut>(self: &Self, buf: &mut B) -> io::Result<usize> { /* ... */ }Tries to read data from the stream into the provided buffer, advancing the
-
pub async fn writable(self: &Self) -> io::Result<()> { /* ... */ }Waits for the pipe to become writable.
-
pub fn poll_write_ready(self: &Self, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }Polls for write readiness.
-
pub fn try_write(self: &Self, buf: &[u8]) -> io::Result<usize> { /* ... */ }Tries to write a buffer to the pipe, returning how many bytes were
-
pub fn try_write_vectored(self: &Self, buf: &[io::IoSlice<''_>]) -> io::Result<usize> { /* ... */ }Tries to write several buffers to the pipe, returning how many bytes
-
pub fn try_io<R, /* synthetic */ impl FnOnce() -> io::Result<R>: FnOnce() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnOnce() -> io::Result<R>) -> io::Result<R> { /* ... */ }Tries to read or write from the pipe using a user-provided IO operation.
-
pub async fn async_io<R, /* synthetic */ impl FnMut() -> io::Result<R>: FnMut() -> io::Result<R>>(self: &Self, interest: Interest, f: impl FnMut() -> io::Result<R>) -> io::Result<R> { /* ... */ }Reads or writes from the pipe using a user-provided IO operation.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsHandle
-
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
-
-
AsRawHandle
-
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
-
-
AsyncRead
-
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncReadExt
-
AsyncWrite
-
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ } -
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<io::Result<usize>> { /* ... */ } -
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ } -
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncWriteExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct ServerOptions
A builder structure for construct a named pipe with named pipe-specific options. This is required to use for named pipe servers who wants to modify pipe-related options.
See [ServerOptions::create].
pub struct ServerOptions {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new() -> ServerOptions { /* ... */ }Creates a new named pipe builder with the default settings.
-
pub fn pipe_mode(self: &mut Self, pipe_mode: PipeMode) -> &mut Self { /* ... */ }The pipe mode.
-
pub fn access_inbound(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }The flow of data in the pipe goes from client to server only.
-
pub fn access_outbound(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }The flow of data in the pipe goes from server to client only.
-
pub fn first_pipe_instance(self: &mut Self, first: bool) -> &mut Self { /* ... */ }If you attempt to create multiple instances of a pipe with this flag
-
pub fn write_dac(self: &mut Self, requested: bool) -> &mut Self { /* ... */ }Requests permission to modify the pipe's discretionary access control list.
-
pub fn write_owner(self: &mut Self, requested: bool) -> &mut Self { /* ... */ }Requests permission to modify the pipe's owner.
-
pub fn access_system_security(self: &mut Self, requested: bool) -> &mut Self { /* ... */ }Requests permission to modify the pipe's system access control list.
-
pub fn reject_remote_clients(self: &mut Self, reject: bool) -> &mut Self { /* ... */ }Indicates whether this server can accept remote clients or not. Remote
-
pub fn max_instances(self: &mut Self, instances: usize) -> &mut Self { /* ... */ }The maximum number of instances that can be created for this pipe. The
-
pub fn out_buffer_size(self: &mut Self, buffer: u32) -> &mut Self { /* ... */ }The number of bytes to reserve for the output buffer.
-
pub fn in_buffer_size(self: &mut Self, buffer: u32) -> &mut Self { /* ... */ }The number of bytes to reserve for the input buffer.
-
pub fn create</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>) -> io::Result<NamedPipeServer> { /* ... */ }Creates the named pipe identified by
addrfor use as a server. -
pub unsafe fn create_with_security_attributes_raw</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>, attrs: *mut c_void) -> io::Result<NamedPipeServer> { /* ... */ }Creates the named pipe identified by
addrfor use as a server.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> ServerOptions { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct ClientOptions
A builder suitable for building and interacting with named pipes from the client side.
See [ClientOptions::open].
pub struct ClientOptions {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new() -> Self { /* ... */ }Creates a new named pipe builder with the default settings.
-
pub fn read(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }If the client supports reading data. This is enabled by default.
-
pub fn write(self: &mut Self, allowed: bool) -> &mut Self { /* ... */ }If the created pipe supports writing data. This is enabled by default.
-
pub fn security_qos_flags(self: &mut Self, flags: u32) -> &mut Self { /* ... */ }Sets qos flags which are combined with other flags and attributes in the
-
pub fn pipe_mode(self: &mut Self, pipe_mode: PipeMode) -> &mut Self { /* ... */ }The pipe mode.
-
pub fn open</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>) -> io::Result<NamedPipeClient> { /* ... */ }Opens the named pipe identified by
addr. -
pub unsafe fn open_with_security_attributes_raw</* synthetic */ impl AsRef<OsStr>: AsRef<OsStr>>(self: &Self, addr: impl AsRef<OsStr>, attrs: *mut c_void) -> io::Result<NamedPipeClient> { /* ... */ }Opens the named pipe identified by
addr.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> ClientOptions { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum PipeMode
Attributes:
NonExhaustive
The pipe mode of a named pipe.
Set through [ServerOptions::pipe_mode].
pub enum PipeMode {
Byte,
Message,
}
Variants
Byte
Data is written to the pipe as a stream of bytes. The pipe does not distinguish bytes written during different write operations.
Corresponds to PIPE_TYPE_BYTE.
Message
Data is written to the pipe as a stream of messages. The pipe treats the
bytes written during each write operation as a message unit. Any reading
on a named pipe returns ERROR_MORE_DATA when a message is not read
completely.
Corresponds to PIPE_TYPE_MESSAGE.
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> PipeMode { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Eq
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Hash
-
fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H) { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &PipeMode) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum PipeEnd
Attributes:
NonExhaustive
Indicates the end of a named pipe.
pub enum PipeEnd {
Client,
Server,
}
Variants
Client
The named pipe refers to the client end of a named pipe instance.
Corresponds to PIPE_CLIENT_END.
Server
The named pipe refers to the server end of a named pipe instance.
Corresponds to PIPE_SERVER_END.
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> PipeEnd { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Eq
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Hash
-
fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H) { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &PipeEnd) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct PipeInfo
Attributes:
NonExhaustive
Information about a named pipe.
Constructed through [NamedPipeServer::info] or [NamedPipeClient::info].
pub struct PipeInfo {
pub mode: PipeMode,
pub end: PipeEnd,
pub max_instances: u32,
pub out_buffer_size: u32,
pub in_buffer_size: u32,
}
Fields
| Name | Type | Documentation |
|---|---|---|
mode |
PipeMode |
Indicates the mode of a named pipe. |
end |
PipeEnd |
Indicates the end of a named pipe. |
max_instances |
u32 |
The maximum number of instances that can be created for this pipe. |
out_buffer_size |
u32 |
The number of bytes to reserve for the output buffer. |
in_buffer_size |
u32 |
The number of bytes to reserve for the input buffer. |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> PipeInfo { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Re-exports
Re-export ToSocketAddrs
pub use addr::ToSocketAddrs;
Re-export lookup_host
Attributes:
Other("#[<cfg>(feature = \"net\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")Other("#[doc(cfg(feature = \"net\"))]")
pub use lookup_host::lookup_host;
Re-export TcpListener
Attributes:
Other("#[<cfg>(feature = \"net\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")Other("#[doc(cfg(feature = \"net\"))]")
pub use tcp::listener::TcpListener;
Re-export TcpStream
Attributes:
Other("#[<cfg>(feature = \"net\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"net\")))]")Other("#[doc(cfg(feature = \"net\"))]")
pub use tcp::stream::TcpStream;
Re-export TcpSocket
Attributes:
Other("#[<cfg>(not(target_os = \"wasi\"))]")
pub use tcp::socket::TcpSocket;
Re-export UdpSocket
Attributes:
Other("#[<cfg>(not(target_os = \"wasi\"))]")Other("#[doc(inline)]")
pub use udp::UdpSocket;
Re-export UnixDatagram
Attributes:
Other("#[<cfg>(all(unix, feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")Other("#[doc(cfg(all(unix, feature = \"net\")))]")
pub use unix::datagram::socket::UnixDatagram;
Re-export UnixListener
Attributes:
Other("#[<cfg>(all(unix, feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")Other("#[doc(cfg(all(unix, feature = \"net\")))]")
pub use unix::listener::UnixListener;
Re-export UnixStream
Attributes:
Other("#[<cfg>(all(unix, feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")Other("#[doc(cfg(all(unix, feature = \"net\")))]")
pub use unix::stream::UnixStream;
Re-export UnixSocket
Attributes:
Other("#[<cfg>(all(unix, feature = \"net\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"net\"))))]")Other("#[doc(cfg(all(unix, feature = \"net\")))]")
pub use unix::socket::UnixSocket;
Module process
Attributes:
Other("#[<cfg>(feature = \"process\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"process\")))]")Other("#[doc(cfg(feature = \"process\"))]")Other("#[<cfg>(not(loom))]")Other("#[<cfg>(not(target_os = \"wasi\"))]")
An implementation of asynchronous process management for Tokio.
This module provides a Command struct that imitates the interface of the
std::process::Command type in the standard library, but provides asynchronous versions of
functions that create processes. These functions (spawn, status, output and their
variants) return "future aware" types that interoperate with Tokio. The asynchronous process
support is provided through signal handling on Unix and system APIs on Windows.
Examples
Here's an example program which will spawn echo hello world and then wait
for it complete.
use tokio::process::Command;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// The usage is similar as with the standard library's `Command` type
let mut child = Command::new("echo")
.arg("hello")
.arg("world")
.spawn()
.expect("failed to spawn");
// Await until the command completes
let status = child.wait().await?;
println!("the command exited with: {}", status);
Ok(())
}
Next, let's take a look at an example where we not only spawn echo hello world but we also capture its output.
use tokio::process::Command;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Like above, but use `output` which returns a future instead of
// immediately returning the `Child`.
let output = Command::new("echo").arg("hello").arg("world")
.output();
let output = output.await?;
assert!(output.status.success());
assert_eq!(output.stdout, b"hello world\n");
Ok(())
}
We can also read input line by line.
use tokio::io::{BufReader, AsyncBufReadExt};
use tokio::process::Command;
use std::process::Stdio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::new("cat");
// Specify that we want the command's standard output piped back to us.
// By default, standard input/output/error will be inherited from the
// current process (for example, this means that standard input will
// come from the keyboard and standard output/error will go directly to
// the terminal if this process is invoked from the command line).
cmd.stdout(Stdio::piped());
let mut child = cmd.spawn()
.expect("failed to spawn command");
let stdout = child.stdout.take()
.expect("child did not have a handle to stdout");
let mut reader = BufReader::new(stdout).lines();
// Ensure the child process is spawned in the runtime so it can
// make progress on its own while we await for any output.
tokio::spawn(async move {
let status = child.wait().await
.expect("child process encountered an error");
println!("child status was: {}", status);
});
while let Some(line) = reader.next_line().await? {
println!("Line: {}", line);
}
Ok(())
}
Here is another example using sort writing into the child process
standard input, capturing the output of the sorted text.
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
use std::process::Stdio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::new("sort");
// Specifying that we want pipe both the output and the input.
// Similarly to capturing the output, by configuring the pipe
// to stdin it can now be used as an asynchronous writer.
cmd.stdout(Stdio::piped());
cmd.stdin(Stdio::piped());
let mut child = cmd.spawn().expect("failed to spawn command");
// These are the animals we want to sort
let animals: &[&str] = &["dog", "bird", "frog", "cat", "fish"];
let mut stdin = child
.stdin
.take()
.expect("child did not have a handle to stdin");
// Write our animals to the child process
// Note that the behavior of `sort` is to buffer _all input_ before writing any output.
// In the general sense, it is recommended to write to the child in a separate task as
// awaiting its exit (or output) to avoid deadlocks (for example, the child tries to write
// some output but gets stuck waiting on the parent to read from it, meanwhile the parent
// is stuck waiting to write its input completely before reading the output).
stdin
.write(animals.join("\n").as_bytes())
.await
.expect("could not write to stdin");
// We drop the handle here which signals EOF to the child process.
// This tells the child process that it there is no more data on the pipe.
drop(stdin);
let op = child.wait_with_output().await?;
// Results should come back in sorted order
assert_eq!(op.stdout, "bird\ncat\ndog\nfish\nfrog\n".as_bytes());
Ok(())
}
With some coordination, we can also pipe the output of one command into another.
use tokio::join;
use tokio::process::Command;
use std::process::Stdio;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut echo = Command::new("echo")
.arg("hello world!")
.stdout(Stdio::piped())
.spawn()
.expect("failed to spawn echo");
let tr_stdin: Stdio = echo
.stdout
.take()
.unwrap()
.try_into()
.expect("failed to convert to Stdio");
let tr = Command::new("tr")
.arg("a-z")
.arg("A-Z")
.stdin(tr_stdin)
.stdout(Stdio::piped())
.spawn()
.expect("failed to spawn tr");
let (echo_result, tr_output) = join!(echo.wait(), tr.wait_with_output());
assert!(echo_result.unwrap().success());
let tr_output = tr_output.expect("failed to await tr");
assert!(tr_output.status.success());
assert_eq!(tr_output.stdout, b"HELLO WORLD!\n");
Ok(())
}
Caveats
Dropping/Cancellation
Similar to the behavior to the standard library, and unlike the futures
paradigm of dropping-implies-cancellation, a spawned process will, by
default, continue to execute even after the Child handle has been dropped.
The Command::kill_on_drop method can be used to modify this behavior
and kill the child process if the Child wrapper is dropped before it
has exited.
Unix Processes
On Unix platforms processes must be "reaped" by their parent process after they have exited in order to release all OS resources. A child process which has exited, but has not yet been reaped by its parent is considered a "zombie" process. Such processes continue to count against limits imposed by the system, and having too many zombie processes present can prevent additional processes from being spawned.
The tokio runtime will, on a best-effort basis, attempt to reap and clean up any process which it has spawned. No additional guarantees are made with regard to how quickly or how often this procedure will take place.
It is recommended to avoid dropping a Child process handle before it has been
fully awaited if stricter cleanup guarantees are required.
pub mod process { /* ... */ }
Types
Struct Command
This structure mimics the API of std::process::Command found in the standard library, but
replaces functions that create a process with an asynchronous variant. The main provided
asynchronous functions are spawn, status, and
output.
Command uses asynchronous versions of some std types (for example Child).
pub struct Command {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new<S: AsRef<OsStr>>(program: S) -> Command { /* ... */ }Constructs a new
Commandfor launching the program at -
pub fn as_std(self: &Self) -> &StdCommand { /* ... */ }Cheaply convert to a
&std::process::Commandfor places where the type from the standard -
pub fn as_std_mut(self: &mut Self) -> &mut StdCommand { /* ... */ }Cheaply convert to a
&mut std::process::Commandfor places where the type from the -
pub fn into_std(self: Self) -> StdCommand { /* ... */ }Cheaply convert into a
std::process::Command. -
pub fn arg<S: AsRef<OsStr>>(self: &mut Self, arg: S) -> &mut Command { /* ... */ }Adds an argument to pass to the program.
-
pub fn args<I, S>(self: &mut Self, args: I) -> &mut Command
where I: IntoIterator<Item = S>, S: AsRef { /* ... */ }
Adds multiple arguments to pass to the program.
- ```rust
pub fn raw_arg<S: AsRef<OsStr>>(self: &mut Self, text_to_append_as_is: S) -> &mut Command { /* ... */ }
Append literal text to the command line without any quoting or escaping.
-
pub fn env<K, V>(self: &mut Self, key: K, val: V) -> &mut Command
where K: AsRef, V: AsRef { /* ... */ }
Inserts or updates an environment variable mapping.
- ```rust
pub fn envs<I, K, V>(self: &mut Self, vars: I) -> &mut Command
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>,
V: AsRef<OsStr> { /* ... */ }
Adds or updates multiple environment variable mappings.
-
pub fn env_remove<K: AsRef<OsStr>>(self: &mut Self, key: K) -> &mut Command { /* ... */ }Removes an environment variable mapping.
-
pub fn env_clear(self: &mut Self) -> &mut Command { /* ... */ }Clears the entire environment map for the child process.
-
pub fn current_dir<P: AsRef<Path>>(self: &mut Self, dir: P) -> &mut Command { /* ... */ }Sets the working directory for the child process.
-
pub fn stdin<T: Into<Stdio>>(self: &mut Self, cfg: T) -> &mut Command { /* ... */ }Sets configuration for the child process's standard input (stdin) handle.
-
pub fn stdout<T: Into<Stdio>>(self: &mut Self, cfg: T) -> &mut Command { /* ... */ }Sets configuration for the child process's standard output (stdout) handle.
-
pub fn stderr<T: Into<Stdio>>(self: &mut Self, cfg: T) -> &mut Command { /* ... */ }Sets configuration for the child process's standard error (stderr) handle.
-
pub fn kill_on_drop(self: &mut Self, kill_on_drop: bool) -> &mut Command { /* ... */ }Controls whether a
killoperation should be invoked on a spawned child -
pub fn creation_flags(self: &mut Self, flags: u32) -> &mut Command { /* ... */ }Sets the [process creation flags][1] to be passed to
CreateProcess. -
pub fn uid(self: &mut Self, id: u32) -> &mut Command { /* ... */ }Sets the child process's user ID. This translates to a
-
pub fn gid(self: &mut Self, id: u32) -> &mut Command { /* ... */ }Similar to
uidbut sets the group ID of the child process. This has -
pub fn arg0<S>(self: &mut Self, arg: S) -> &mut Command
where S: AsRef { /* ... */ }
Sets executable argument.
- ```rust
pub unsafe fn pre_exec<F>(self: &mut Self, f: F) -> &mut Command
where
F: FnMut() -> io::Result<()> + Send + Sync + ''static { /* ... */ }
Schedules a closure to be run just before the exec function is
-
pub fn process_group(self: &mut Self, pgroup: i32) -> &mut Command { /* ... */ }Sets the process group ID (PGID) of the child process. Equivalent to a
-
pub fn spawn(self: &mut Self) -> io::Result<Child> { /* ... */ }Executes the command as a child process, returning a handle to it.
-
pub fn spawn_with</* synthetic */ impl FnOnce(&mut StdCommand) -> io::Result<StdChild>: FnOnce(&mut StdCommand) -> io::Result<StdChild>>(self: &mut Self, with: impl FnOnce(&mut StdCommand) -> io::Result<StdChild>) -> io::Result<Child> { /* ... */ }Executes the command as a child process with a custom spawning function,
-
pub fn status(self: &mut Self) -> impl Future<Output = io::Result<ExitStatus>> { /* ... */ }Executes the command as a child process, waiting for it to finish and
-
pub fn output(self: &mut Self) -> impl Future<Output = io::Result<Output>> { /* ... */ }Executes the command as a child process, waiting for it to finish and
-
pub fn get_kill_on_drop(self: &Self) -> bool { /* ... */ }Returns the boolean value that was previously set by
Command::kill_on_drop.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
fn from(t: T) -> T { /* ... */ }Returns the argument unchanged.
-
fn from(std: StdCommand) -> Command { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Child
Representation of a child process spawned onto an event loop.
Caveats
Similar to the behavior to the standard library, and unlike the futures
paradigm of dropping-implies-cancellation, a spawned process will, by
default, continue to execute even after the Child handle has been dropped.
The Command::kill_on_drop method can be used to modify this behavior
and kill the child process if the Child wrapper is dropped before it
has exited.
pub struct Child {
pub stdin: Option<ChildStdin>,
pub stdout: Option<ChildStdout>,
pub stderr: Option<ChildStderr>,
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
stdin |
Option<ChildStdin> |
The handle for writing to the child's standard input (stdin), if it has been captured. To avoid partially moving the child and thus blockingyourself from calling functions on child while using stdin, you mightfind it helpful to do: no_run<br># let mut child = tokio::process::Command::new("echo").spawn().unwrap();<br>let stdin = child.stdin.take().unwrap();<br> |
stdout |
Option<ChildStdout> |
The handle for reading from the child's standard output (stdout), if it has been captured. You might find it helpful to do no_run<br># let mut child = tokio::process::Command::new("echo").spawn().unwrap();<br>let stdout = child.stdout.take().unwrap();<br>to avoid partially moving the child and thus blocking yourself from callingfunctions on child while using stdout. |
stderr |
Option<ChildStderr> |
The handle for reading from the child's standard error (stderr), if it has been captured. You might find it helpful to do no_run<br># let mut child = tokio::process::Command::new("echo").spawn().unwrap();<br>let stderr = child.stderr.take().unwrap();<br>to avoid partially moving the child and thus blocking yourself from callingfunctions on child while using stderr. |
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn id(self: &Self) -> Option<u32> { /* ... */ }Returns the OS-assigned process identifier associated with this child
-
pub fn raw_handle(self: &Self) -> Option<RawHandle> { /* ... */ }Extracts the raw handle of the process associated with this child while
-
pub fn start_kill(self: &mut Self) -> io::Result<()> { /* ... */ }Attempts to force the child to exit, but does not wait for the request
-
pub async fn kill(self: &mut Self) -> io::Result<()> { /* ... */ }Forces the child to exit.
-
pub async fn wait(self: &mut Self) -> io::Result<ExitStatus> { /* ... */ }Waits for the child to exit completely, returning the status that it
-
pub fn try_wait(self: &mut Self) -> io::Result<Option<ExitStatus>> { /* ... */ }Attempts to collect the exit status of the child if it has already
-
pub async fn wait_with_output(self: Self) -> io::Result<Output> { /* ... */ }Returns a future that will resolve to an
Output, containing the exit
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct ChildStdin
The standard input stream for spawned children.
This type implements the AsyncWrite trait to pass data to the stdin
handle of a child process asynchronously.
pub struct ChildStdin {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn into_owned_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Convert into [
OwnedFd]. -
pub fn into_owned_handle(self: Self) -> io::Result<OwnedHandle> { /* ... */ }Convert into [
OwnedHandle]. -
pub fn from_std(inner: std::process::ChildStdin) -> io::Result<Self> { /* ... */ }Creates an asynchronous
ChildStdinfrom a synchronous one.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsFd
-
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
-
-
AsHandle
-
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
-
-
AsRawFd
-
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
-
-
AsRawHandle
-
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
-
-
AsyncWrite
-
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &[u8]) -> Poll<io::Result<usize>> { /* ... */ } -
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ } -
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<io::Result<()>> { /* ... */ } -
fn poll_write_vectored(self: Pin<&mut Self>, cx: &mut Context<''_>, bufs: &[io::IoSlice<''_>]) -> Poll<Result<usize, io::Error>> { /* ... */ } -
fn is_write_vectored(self: &Self) -> bool { /* ... */ }
-
-
AsyncWriteExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ } -
fn try_into(self: Self) -> Result<Stdio, <Self as >::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct ChildStdout
The standard output stream for spawned children.
This type implements the AsyncRead trait to read data from the stdout
handle of a child process asynchronously.
pub struct ChildStdout {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn into_owned_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Convert into [
OwnedFd]. -
pub fn into_owned_handle(self: Self) -> io::Result<OwnedHandle> { /* ... */ }Convert into [
OwnedHandle]. -
pub fn from_std(inner: std::process::ChildStdout) -> io::Result<Self> { /* ... */ }Creates an asynchronous
ChildStdoutfrom a synchronous one.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsFd
-
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
-
-
AsHandle
-
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
-
-
AsRawFd
-
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
-
-
AsRawHandle
-
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
-
-
AsyncRead
-
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncReadExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ } -
fn try_into(self: Self) -> Result<Stdio, <Self as >::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct ChildStderr
The standard error stream for spawned children.
This type implements the AsyncRead trait to read data from the stderr
handle of a child process asynchronously.
pub struct ChildStderr {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn into_owned_fd(self: Self) -> io::Result<OwnedFd> { /* ... */ }Convert into [
OwnedFd]. -
pub fn into_owned_handle(self: Self) -> io::Result<OwnedHandle> { /* ... */ }Convert into [
OwnedHandle]. -
pub fn from_std(inner: std::process::ChildStderr) -> io::Result<Self> { /* ... */ }Creates an asynchronous
ChildStderrfrom a synchronous one.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
AsFd
-
fn as_fd(self: &Self) -> BorrowedFd<''_> { /* ... */ }
-
-
AsHandle
-
fn as_handle(self: &Self) -> BorrowedHandle<''_> { /* ... */ }
-
-
AsRawFd
-
fn as_raw_fd(self: &Self) -> RawFd { /* ... */ }
-
-
AsRawHandle
-
fn as_raw_handle(self: &Self) -> RawHandle { /* ... */ }
-
-
AsyncRead
-
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<''_>, buf: &mut ReadBuf<''_>) -> Poll<io::Result<()>> { /* ... */ }
-
-
AsyncReadExt
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ } -
fn try_into(self: Self) -> Result<Stdio, <Self as >::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Module runtime
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
The Tokio runtime.
Unlike other Rust programs, asynchronous applications require runtime support. In particular, the following runtime services are necessary:
- An I/O event loop, called the driver, which drives I/O resources and dispatches I/O events to tasks that depend on them.
- A scheduler to execute tasks that use these I/O resources.
- A timer for scheduling work to run after a set period of time.
Tokio's Runtime bundles all of these services as a single type, allowing
them to be started, shut down, and configured together. However, often it is
not required to configure a Runtime manually, and a user may just use the
tokio::main attribute macro, which creates a Runtime under the hood.
Choose your runtime
Here is the rules of thumb to choose the right runtime for your application.
+------------------------------------------------------+
| Do you want work-stealing or multi-thread scheduler? |
+------------------------------------------------------+
| Yes | No
| |
| |
v |
+------------------------+ |
| Multi-threaded Runtime | |
+------------------------+ |
|
V
+--------------------------------+
| Do you execute `!Send` Future? |
+--------------------------------+
| Yes | No
| |
V |
+--------------------------+ |
| Local Runtime (unstable) | |
+--------------------------+ |
|
v
+------------------------+
| Current-thread Runtime |
+------------------------+
The above decision tree is not exhaustive. there are other factors that may influence your decision.
Bridging with sync code
See https://tokio.rs/tokio/topics/bridging for details.
NUMA awareness
The tokio runtime is not NUMA (Non-Uniform Memory Access) aware. You may want to start multiple runtimes instead of a single runtime for better performance on NUMA systems.
Usage
When no fine tuning is required, the tokio::main attribute macro can be
used.
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
// In a loop, read data from the socket and write the data back.
loop {
let n = match socket.read(&mut buf).await {
// socket closed
Ok(0) => return,
Ok(n) => n,
Err(e) => {
println!("failed to read from socket; err = {:?}", e);
return;
}
};
// Write the data back
if let Err(e) = socket.write_all(&buf[0..n]).await {
println!("failed to write to socket; err = {:?}", e);
return;
}
}
});
}
}
# }
From within the context of the runtime, additional tasks are spawned using
the tokio::spawn function. Futures spawned using this function will be
executed on the same thread pool used by the Runtime.
A Runtime instance can also be used directly.
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::runtime::Runtime;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create the runtime
let rt = Runtime::new()?;
// Spawn the root task
rt.block_on(async {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
loop {
let (mut socket, _) = listener.accept().await?;
tokio::spawn(async move {
let mut buf = [0; 1024];
// In a loop, read data from the socket and write the data back.
loop {
let n = match socket.read(&mut buf).await {
// socket closed
Ok(0) => return,
Ok(n) => n,
Err(e) => {
println!("failed to read from socket; err = {:?}", e);
return;
}
};
// Write the data back
if let Err(e) = socket.write_all(&buf[0..n]).await {
println!("failed to write to socket; err = {:?}", e);
return;
}
}
});
}
})
}
# }
Runtime Configurations
Tokio provides multiple task scheduling strategies, suitable for different
applications. The runtime builder or #[tokio::main] attribute may be
used to select which scheduler to use.
Multi-Thread Scheduler
The multi-thread scheduler executes futures on a thread pool, using a
work-stealing strategy. By default, it will start a worker thread for each
CPU core available on the system. This tends to be the ideal configuration
for most applications. The multi-thread scheduler requires the rt-multi-thread
feature flag, and is selected by default:
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::runtime;
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let threaded_rt = runtime::Runtime::new()?;
# Ok(()) }
# }
Most applications should use the multi-thread scheduler, except in some niche use-cases, such as when running only a single thread is required.
Current-Thread Scheduler
The current-thread scheduler provides a single-threaded future executor.
All tasks will be created and executed on the current thread. This requires
the rt feature flag.
use tokio::runtime;
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let rt = runtime::Builder::new_current_thread()
.build()?;
# Ok(()) }
Resource drivers
When configuring a runtime by hand, no resource drivers are enabled by
default. In this case, attempting to use networking types or time types will
fail. In order to enable these types, the resource drivers must be enabled.
This is done with Builder::enable_io and Builder::enable_time. As a
shorthand, Builder::enable_all enables both resource drivers.
Lifetime of spawned threads
The runtime may spawn threads depending on its configuration and usage. The
multi-thread scheduler spawns threads to schedule tasks and for spawn_blocking
calls.
While the Runtime is active, threads may shut down after periods of being
idle. Once Runtime is dropped, all runtime threads have usually been
terminated, but in the presence of unstoppable spawned work are not
guaranteed to have been terminated. See the
struct level documentation for more details.
Detailed runtime behavior
This section gives more details into how the Tokio runtime will schedule tasks for execution.
At its most basic level, a runtime has a collection of tasks that need to be
scheduled. It will repeatedly remove a task from that collection and
schedule it (by calling poll). When the collection is empty, the thread
will go to sleep until a task is added to the collection.
However, the above is not sufficient to guarantee a well-behaved runtime. For example, the runtime might have a single task that is always ready to be scheduled, and schedule that task every time. This is a problem because it starves other tasks by not scheduling them. To solve this, Tokio provides the following fairness guarantee:
If the total number of tasks does not grow without bound, and no task is blocking the thread, then it is guaranteed that tasks are scheduled fairly.
Or, more formally:
Under the following two assumptions:
- There is some number
MAX_TASKSsuch that the total number of tasks on the runtime at any specific point in time never exceedsMAX_TASKS.- There is some number
MAX_SCHEDULEsuch that callingpollon any task spawned on the runtime returns withinMAX_SCHEDULEtime units.Then, there is some number
MAX_DELAYsuch that when a task is woken, it will be scheduled by the runtime withinMAX_DELAYtime units.
(Here, MAX_TASKS and MAX_SCHEDULE can be any number and the user of
the runtime may choose them. The MAX_DELAY number is controlled by the
runtime, and depends on the value of MAX_TASKS and MAX_SCHEDULE.)
Other than the above fairness guarantee, there is no guarantee about the
order in which tasks are scheduled. There is also no guarantee that the
runtime is equally fair to all tasks. For example, if the runtime has two
tasks A and B that are both ready, then the runtime may schedule A five
times before it schedules B. This is the case even if A yields using
yield_now. All that is guaranteed is that it will schedule B eventually.
Normally, tasks are scheduled only if they have been woken by calling
wake on their waker. However, this is not guaranteed, and Tokio may
schedule tasks that have not been woken under some circumstances. This is
called a spurious wakeup.
IO and timers
Beyond just scheduling tasks, the runtime must also manage IO resources and timers. It does this by periodically checking whether there are any IO resources or timers that are ready, and waking the relevant task so that it will be scheduled.
These checks are performed periodically between scheduling tasks. Under the same assumptions as the previous fairness guarantee, Tokio guarantees that it will wake tasks with an IO or timer event within some maximum number of time units.
Current thread runtime (behavior at the time of writing)
This section describes how the current thread runtime behaves today. This behavior may change in future versions of Tokio.
The current thread runtime maintains two FIFO queues of tasks that are ready
to be scheduled: the global queue and the local queue. The runtime will prefer
to choose the next task to schedule from the local queue, and will only pick a
task from the global queue if the local queue is empty, or if it has picked
a task from the local queue 31 times in a row. The number 31 can be
changed using the global_queue_interval setting.
The runtime will check for new IO or timer events whenever there are no
tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The
number 61 may be changed using the event_interval setting.
When a task is woken from within a task running on the runtime, then the woken task is added directly to the local queue. Otherwise, the task is added to the global queue. The current thread runtime does not use the lifo slot optimization.
Multi threaded runtime (behavior at the time of writing)
This section describes how the multi thread runtime behaves today. This behavior may change in future versions of Tokio.
A multi thread runtime has a fixed number of worker threads, which are all created on startup. The multi thread runtime maintains one global queue, and a local queue for each worker thread. The local queue of a worker thread can fit at most 256 tasks. If more than 256 tasks are added to the local queue, then half of them are moved to the global queue to make space.
The runtime will prefer to choose the next task to schedule from the local
queue, and will only pick a task from the global queue if the local queue is
empty, or if it has picked a task from the local queue
global_queue_interval times in a row. If the value of
global_queue_interval is not explicitly set using the runtime builder,
then the runtime will dynamically compute it using a heuristic that targets
10ms intervals between each check of the global queue (based on the
worker_mean_poll_time metric).
If both the local queue and global queue is empty, then the worker thread will attempt to steal tasks from the local queue of another worker thread. Stealing is done by moving half of the tasks in one local queue to another local queue.
The runtime will check for new IO or timer events whenever there are no
tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The
number 61 may be changed using the event_interval setting.
The multi thread runtime uses the lifo slot optimization: Whenever a task
wakes up another task, the other task is added to the worker thread's lifo
slot instead of being added to a queue. If there was already a task in the
lifo slot when this happened, then the lifo slot is replaced, and the task
that used to be in the lifo slot is placed in the thread's local queue.
When the runtime finishes scheduling a task, it will schedule the task in
the lifo slot immediately, if any. When the lifo slot is used, the coop
budget is not reset. Furthermore, if a worker thread uses the lifo slot
three times in a row, it is temporarily disabled until the worker thread has
scheduled a task that didn't come from the lifo slot. The lifo slot can be
disabled using the disable_lifo_slot setting. The lifo slot is separate
from the local queue, so other worker threads cannot steal the task in the
lifo slot.
When a task is woken from a thread that is not a worker thread, then the task is placed in the global queue.
pub mod runtime { /* ... */ }
Modules
Module dump
Attributes:
Other("#[<cfg>(all(tokio_unstable, feature = \"taskdump\", feature = \"rt\", target_os =\n\"linux\",\nany(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\")))]")
Snapshots of runtime state.
See [Handle::dump][crate::runtime::Handle::dump].
pub mod dump { /* ... */ }
Types
Struct Dump
A snapshot of a runtime's state.
See [Handle::dump][crate::runtime::Handle::dump].
pub struct Dump {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
Tasks in this snapshot.
pub fn tasks(self: &Self) -> &Tasks { /* ... */ }
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Tasks
Snapshots of tasks.
See [Handle::dump][crate::runtime::Handle::dump].
pub struct Tasks {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
Iterate over tasks.
pub fn iter(self: &Self) -> impl Iterator<Item = &Task> { /* ... */ }
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Task
A snapshot of a task.
See [Handle::dump][crate::runtime::Handle::dump].
pub struct Task {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn id(self: &Self) -> Id { /* ... */ }Returns a task ID that uniquely identifies this task relative to other
-
pub fn trace(self: &Self) -> &Trace { /* ... */ }A trace of this task's state.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct BacktraceSymbol
A backtrace symbol.
This struct provides accessors for backtrace symbols, similar to [backtrace::BacktraceSymbol].
pub struct BacktraceSymbol {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn name_raw(self: &Self) -> Option<&[u8]> { /* ... */ }Return the raw name of the symbol.
-
pub fn name_demangled(self: &Self) -> Option<&str> { /* ... */ }Return the demangled name of the symbol.
-
pub fn addr(self: &Self) -> Option<*mut std::ffi::c_void> { /* ... */ }Returns the starting address of this symbol.
-
pub fn filename(self: &Self) -> Option<&Path> { /* ... */ }Returns the file name where this function was defined. If debuginfo
-
pub fn lineno(self: &Self) -> Option<u32> { /* ... */ }Returns the line number for where this symbol is currently executing.
-
pub fn colno(self: &Self) -> Option<u32> { /* ... */ }Returns the column number for where this symbol is currently executing.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> BacktraceSymbol { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct BacktraceFrame
A backtrace frame.
This struct represents one stack frame in a captured backtrace, similar to [backtrace::BacktraceFrame].
pub struct BacktraceFrame {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn ip(self: &Self) -> *mut std::ffi::c_void { /* ... */ }Return the instruction pointer of this frame.
-
pub fn symbol_address(self: &Self) -> *mut std::ffi::c_void { /* ... */ }Returns the starting symbol address of the frame of this function.
-
pub fn symbols(self: &Self) -> impl Iterator<Item = &BacktraceSymbol> { /* ... */ }Return an iterator over the symbols of this backtrace frame.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> BacktraceFrame { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Backtrace
A captured backtrace.
This struct provides access to each backtrace frame, similar to [backtrace::Backtrace].
pub struct Backtrace {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
Return the frames in this backtrace, innermost (in a task dump,
pub fn frames(self: &Self) -> impl Iterator<Item = &BacktraceFrame> { /* ... */ }
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> Backtrace { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Trace
An execution trace of a task's last poll.
Resolving a backtrace, either via the [Display][std::fmt::Display] impl or via
[resolve_backtraces][Trace::resolve_backtraces], parses debuginfo, which is
possibly a CPU-expensive operation that can take a platform-specific but
long time to run - often over 100 milliseconds, especially if the current
process's binary is big. In some cases, the platform might internally cache some of the
debuginfo, so successive calls to resolve_backtraces might be faster than
the first call, but all guarantees are platform-dependent.
To avoid blocking the runtime, it is recommended
that you resolve backtraces inside of a [spawn_blocking()][crate::task::spawn_blocking]
and to have some concurrency-limiting mechanism to avoid unexpected performance impact.
See [Handle::dump][crate::runtime::Handle::dump].
pub struct Trace {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn resolve_backtraces(self: &Self) -> Vec<Backtrace> { /* ... */ }Resolve and return a list of backtraces that are involved in polls in this trace.
-
pub fn capture<F, R>(f: F) -> (R, Trace)
where F: FnOnce() -> R { /* ... */ }
Runs the function `f` in tracing mode, and returns its result along with the resulting [`Trace`].
- ```rust
pub fn root<F>(f: F) -> Root<F>
where
F: Future { /* ... */ }
Create a root for stack traces captured using [Trace::capture]. Stack frames above
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Re-exports
Re-export Root
pub use crate::runtime::task::trace::Root;
Re-exports
Re-export Builder
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use self::builder::Builder;
Re-export Id
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")Other("#[<cfg_attr>(not(tokio_unstable), allow(unreachable_pub))]")
pub use id::Id;
Re-export UnhandledPanic
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use self::builder::UnhandledPanic;
Re-export RngSeed
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use crate::util::rand::RngSeed;
Re-export LocalRuntime
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use local_runtime::LocalRuntime;
Re-export LocalOptions
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use local_runtime::LocalOptions;
Re-export Dump
Attributes:
Other("#[<cfg>(all(tokio_unstable, feature = \"taskdump\", feature = \"rt\", target_os =\n\"linux\",\nany(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\")))]")
pub use dump::Dump;
Re-export TaskMeta
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use task_hooks::TaskMeta;
Re-export EnterGuard
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use handle::EnterGuard;
Re-export Handle
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use handle::Handle;
Re-export TryCurrentError
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use handle::TryCurrentError;
Re-export Runtime
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use runtime::Runtime;
Re-export RuntimeFlavor
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use runtime::RuntimeFlavor;
Re-export RuntimeMetrics
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use metrics::RuntimeMetrics;
Re-export HistogramScale
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use metrics::HistogramScale;
Re-export HistogramConfiguration
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use metrics::HistogramConfiguration;
Re-export LogHistogram
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use metrics::LogHistogram;
Re-export LogHistogramBuilder
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use metrics::LogHistogramBuilder;
Re-export InvalidHistogramConfiguration
Attributes:
Other("#[<cfg>(tokio_unstable)]")Other("#[<cfg_attr>(docsrs, doc(cfg(tokio_unstable)))]")Other("#[doc(cfg(tokio_unstable))]")
pub use metrics::InvalidHistogramConfiguration;
Module signal
Attributes:
Other("#[<cfg>(feature = \"signal\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"signal\")))]")Other("#[doc(cfg(feature = \"signal\"))]")Other("#[<cfg>(not(loom))]")Other("#[<cfg>(not(target_os = \"wasi\"))]")
Asynchronous signal handling for Tokio.
Note that signal handling is in general a very tricky topic and should be used with great care. This crate attempts to implement 'best practice' for signal handling, but it should be evaluated for your own applications' needs to see if it's suitable.
There are some fundamental limitations of this crate documented on the OS specific structures, as well.
Examples
Print on "ctrl-c" notification.
use tokio::signal;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
signal::ctrl_c().await?;
println!("ctrl-c received!");
Ok(())
}
Wait for SIGHUP on Unix
# #[cfg(unix)] {
use tokio::signal::unix::{signal, SignalKind};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// An infinite stream of hangup signals.
let mut stream = signal(SignalKind::hangup())?;
// Print whenever a HUP signal is received
loop {
stream.recv().await;
println!("got signal HUP");
}
}
# }
pub mod signal { /* ... */ }
Modules
Module unix
Attributes:
Other("#[<cfg>(unix)]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(unix, feature = \"signal\"))))]")Other("#[doc(cfg(all(unix, feature = \"signal\")))]")
Unix-specific types for signal handling.
This module is only defined on Unix platforms and contains the primary
Signal type for receiving notifications of signals.
pub mod unix { /* ... */ }
Types
Struct SignalKind
Represents the specific kind of signal to listen for.
pub struct SignalKind(/* private field */);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | private |
Private field |
Implementations
Methods
-
pub const fn from_raw(signum: std::os::raw::c_int) -> Self { /* ... */ }Allows for listening to any valid OS signal.
-
pub const fn as_raw_value(self: &Self) -> std::os::raw::c_int { /* ... */ }Get the signal's numeric value.
-
pub const fn alarm() -> Self { /* ... */ }Represents the
SIGALRMsignal. -
pub const fn child() -> Self { /* ... */ }Represents the
SIGCHLDsignal. -
pub const fn hangup() -> Self { /* ... */ }Represents the
SIGHUPsignal. -
pub const fn interrupt() -> Self { /* ... */ }Represents the
SIGINTsignal. -
pub const fn io() -> Self { /* ... */ }Represents the
SIGIOsignal. -
pub const fn pipe() -> Self { /* ... */ }Represents the
SIGPIPEsignal. -
pub const fn quit() -> Self { /* ... */ }Represents the
SIGQUITsignal. -
pub const fn terminate() -> Self { /* ... */ }Represents the
SIGTERMsignal. -
pub const fn user_defined1() -> Self { /* ... */ }Represents the
SIGUSR1signal. -
pub const fn user_defined2() -> Self { /* ... */ }Represents the
SIGUSR2signal. -
pub const fn window_change() -> Self { /* ... */ }Represents the
SIGWINCHsignal.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> SignalKind { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Eq
-
Freeze
-
From
-
fn from(t: T) -> T { /* ... */ }Returns the argument unchanged.
-
fn from(signum: std::os::raw::c_int) -> Self { /* ... */ } -
fn from(kind: SignalKind) -> Self { /* ... */ }
-
-
Hash
-
fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H) { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &SignalKind) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Signal
Attributes:
MustUse { reason: Some("streams do nothing unless polled") }
An listener for receiving a particular type of OS signal.
The listener can be turned into a Stream using SignalStream.
In general signal handling on Unix is a pretty tricky topic, and this
structure is no exception! There are some important limitations to keep in
mind when using Signal streams:
-
Signals handling in Unix already necessitates coalescing signals together sometimes. This
Signalstream is also no exception here in that it will also coalesce signals. That is, even if the signal handler for this process runs multiple times, theSignalstream may only return one signal notification. Specifically, beforepollis called, all signal notifications are coalesced into one item returned frompoll. Oncepollhas been called, however, a further signal is guaranteed to be yielded as an item.Put another way, any element pulled off the returned listener corresponds to at least one signal, but possibly more.
-
Signal handling in general is relatively inefficient. Although some improvements are possible in this crate, it's recommended to not plan on having millions of signal channels open.
If you've got any questions about this feel free to open an issue on the repo! New approaches to alleviate some of these limitations are always appreciated!
Caveats
The first time that a Signal instance is registered for a particular
signal kind, an OS signal-handler is installed which replaces the default
platform behavior when that signal is received, for the duration of the
entire process.
For example, Unix systems will terminate a process by default when it
receives SIGINT. But, when a Signal instance is created to listen for
this signal, the next SIGINT that arrives will be translated to a stream
event, and the process will continue to execute. Even if this Signal
instance is dropped, subsequent SIGINT deliveries will end up captured by
Tokio, and the default platform behavior will NOT be reset.
Thus, applications should take care to ensure the expected signal behavior occurs as expected after listening for specific signals.
Examples
Wait for SIGHUP
use tokio::signal::unix::{signal, SignalKind};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// An infinite stream of hangup signals.
let mut sig = signal(SignalKind::hangup())?;
// Print whenever a HUP signal is received
loop {
sig.recv().await;
println!("got signal HUP");
}
}
pub struct Signal {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }Receives the next signal notification event.
-
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }Polls to receive the next signal notification event, outside of an
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function signal
Attributes:
Other("#[attr = TrackCaller]")
Creates a new listener which will receive notifications when the current
process receives the specified signal kind.
This function will create a new stream which binds to the default reactor.
The Signal stream is an infinite stream which will receive
notifications whenever a signal is received. More documentation can be
found on Signal itself, but to reiterate:
- Signals may be coalesced beyond what the kernel already does.
- Once a signal handler is registered with the process the underlying libc signal handler is never unregistered.
A Signal stream can be created for a particular signal number
multiple times. When a signal is received then all the associated
channels will receive the signal notification.
Errors
- If the lower-level C functions fail for some reason.
- If the previous initialization of this specific signal failed.
- If the signal is one of
signal_hook::FORBIDDEN
Panics
This function panics if there is no current reactor set, or if the rt
feature flag is not enabled.
pub fn signal(kind: SignalKind) -> io::Result<Signal> { /* ... */ }
Module windows
Attributes:
Other("#[<cfg>(any(windows, docsrs))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(windows, feature = \"signal\"))))]")Other("#[doc(cfg(all(windows, feature = \"signal\")))]")
Windows-specific types for signal handling.
This module is only defined on Windows and allows receiving "ctrl-c",
"ctrl-break", "ctrl-logoff", "ctrl-shutdown", and "ctrl-close"
notifications. These events are listened for via the SetConsoleCtrlHandler
function which receives the corresponding windows_sys event type.
pub mod windows { /* ... */ }
Types
Struct CtrlC
Attributes:
MustUse { reason: Some("listeners do nothing unless polled") }
Represents a listener which receives "ctrl-c" notifications sent to the process
via SetConsoleCtrlHandler.
This event can be turned into a Stream using CtrlCStream.
A notification to this process notifies all receivers for this event. Moreover, the notifications are coalesced if they aren't processed quickly enough. This means that if two notifications are received back-to-back, then the listener may only receive one item about the two notifications.
pub struct CtrlC {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }Receives the next signal notification event.
-
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }Polls to receive the next signal notification event, outside of an
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct CtrlBreak
Attributes:
MustUse { reason: Some("listeners do nothing unless polled") }
Represents a listener which receives "ctrl-break" notifications sent to the process
via SetConsoleCtrlHandler.
This listener can be turned into a Stream using CtrlBreakStream.
A notification to this process notifies all receivers for this event. Moreover, the notifications are coalesced if they aren't processed quickly enough. This means that if two notifications are received back-to-back, then the listener may only receive one item about the two notifications.
pub struct CtrlBreak {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }Receives the next signal notification event.
-
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }Polls to receive the next signal notification event, outside of an
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct CtrlClose
Attributes:
MustUse { reason: Some("listeners do nothing unless polled") }
Represents a listener which receives "ctrl-close" notifications sent to the process
via SetConsoleCtrlHandler.
A notification to this process notifies all listeners listening for this event. Moreover, the notifications are coalesced if they aren't processed quickly enough. This means that if two notifications are received back-to-back, then the listener may only receive one item about the two notifications.
pub struct CtrlClose {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }Receives the next signal notification event.
-
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }Polls to receive the next signal notification event, outside of an
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct CtrlShutdown
Attributes:
MustUse { reason: Some("listeners do nothing unless polled") }
Represents a listener which receives "ctrl-shutdown" notifications sent to the process
via SetConsoleCtrlHandler.
A notification to this process notifies all listeners listening for this event. Moreover, the notifications are coalesced if they aren't processed quickly enough. This means that if two notifications are received back-to-back, then the listener may only receive one item about the two notifications.
pub struct CtrlShutdown {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }Receives the next signal notification event.
-
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }Polls to receive the next signal notification event, outside of an
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct CtrlLogoff
Attributes:
MustUse { reason: Some("listeners do nothing unless polled") }
Represents a listener which receives "ctrl-logoff" notifications sent to the process
via SetConsoleCtrlHandler.
A notification to this process notifies all listeners listening for this event. Moreover, the notifications are coalesced if they aren't processed quickly enough. This means that if two notifications are received back-to-back, then the listener may only receive one item about the two notifications.
pub struct CtrlLogoff {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub async fn recv(self: &mut Self) -> Option<()> { /* ... */ }Receives the next signal notification event.
-
pub fn poll_recv(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<()>> { /* ... */ }Polls to receive the next signal notification event, outside of an
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function ctrl_c
Creates a new listener which receives "ctrl-c" notifications sent to the process.
Examples
use tokio::signal::windows::ctrl_c;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// A listener of CTRL-C events.
let mut signal = ctrl_c()?;
// Print whenever a CTRL-C event is received.
for countdown in (0..3).rev() {
signal.recv().await;
println!("got CTRL-C. {} more to exit", countdown);
}
Ok(())
}
pub fn ctrl_c() -> io::Result<CtrlC> { /* ... */ }
Function ctrl_break
Creates a new listener which receives "ctrl-break" notifications sent to the process.
Examples
use tokio::signal::windows::ctrl_break;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// A listener of CTRL-BREAK events.
let mut signal = ctrl_break()?;
// Print whenever a CTRL-BREAK event is received.
loop {
signal.recv().await;
println!("got signal CTRL-BREAK");
}
}
pub fn ctrl_break() -> io::Result<CtrlBreak> { /* ... */ }
Function ctrl_close
Creates a new listener which receives "ctrl-close" notifications sent to the process.
Examples
use tokio::signal::windows::ctrl_close;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// A listener of CTRL-CLOSE events.
let mut signal = ctrl_close()?;
// Print whenever a CTRL-CLOSE event is received.
for countdown in (0..3).rev() {
signal.recv().await;
println!("got CTRL-CLOSE. {} more to exit", countdown);
}
Ok(())
}
pub fn ctrl_close() -> io::Result<CtrlClose> { /* ... */ }
Function ctrl_shutdown
Creates a new listener which receives "ctrl-shutdown" notifications sent to the process.
Examples
use tokio::signal::windows::ctrl_shutdown;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// A listener of CTRL-SHUTDOWN events.
let mut signal = ctrl_shutdown()?;
signal.recv().await;
println!("got CTRL-SHUTDOWN. Cleaning up before exiting");
Ok(())
}
pub fn ctrl_shutdown() -> io::Result<CtrlShutdown> { /* ... */ }
Function ctrl_logoff
Creates a new listener which receives "ctrl-logoff" notifications sent to the process.
Examples
use tokio::signal::windows::ctrl_logoff;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// A listener of CTRL-LOGOFF events.
let mut signal = ctrl_logoff()?;
signal.recv().await;
println!("got CTRL-LOGOFF. Cleaning up before exiting");
Ok(())
}
pub fn ctrl_logoff() -> io::Result<CtrlLogoff> { /* ... */ }
Re-exports
Re-export ctrl_c
Attributes:
Other("#[<cfg>(feature = \"signal\")]")
pub use ctrl_c::ctrl_c;
Module sync
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")Other("#[<cfg_attr>(loom, allow(dead_code, unreachable_pub, unused_imports))]")
Synchronization primitives for use in asynchronous contexts.
Tokio programs tend to be organized as a set of tasks where each task operates independently and may be executed on separate physical threads. The synchronization primitives provided in this module permit these independent tasks to communicate together.
Message passing
The most common form of synchronization in a Tokio program is message passing. Two tasks operate independently and send messages to each other to synchronize. Doing so has the advantage of avoiding shared state.
Message passing is implemented using channels. A channel supports sending a message from one producer task to one or more consumer tasks. There are a few flavors of channels provided by Tokio. Each channel flavor supports different message passing patterns. When a channel supports multiple producers, many separate tasks may send messages. When a channel supports multiple consumers, many different separate tasks may receive messages.
Tokio provides many different channel flavors as different message passing patterns are best handled with different implementations.
oneshot channel
The oneshot channel supports sending a single value from a
single producer to a single consumer. This channel is usually used to send
the result of a computation to a waiter.
Example: using a oneshot channel to receive the result of a
computation.
use tokio::sync::oneshot;
async fn some_computation() -> String {
"represents the result of the computation".to_string()
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
let res = some_computation().await;
tx.send(res).unwrap();
});
// Do other work while the computation is happening in the background
// Wait for the computation result
let res = rx.await.unwrap();
# }
Note, if the task produces a computation result as its final
action before terminating, the JoinHandle can be used to
receive that value instead of allocating resources for the
oneshot channel. Awaiting on JoinHandle returns Result. If
the task panics, the Joinhandle yields Err with the panic
cause.
Example:
async fn some_computation() -> String {
"the result of the computation".to_string()
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let join_handle = tokio::spawn(async move {
some_computation().await
});
// Do other work while the computation is happening in the background
// Wait for the computation result
let res = join_handle.await.unwrap();
# }
mpsc channel
The [mpsc channel][mpsc] supports sending many values from many
producers to a single consumer. This channel is often used to send work to a
task or to receive the result of many computations.
This is also the channel you should use if you want to send many messages from a single producer to a single consumer. There is no dedicated spsc channel.
Example: using an mpsc to incrementally stream the results of a series of computations.
use tokio::sync::mpsc;
async fn some_computation(input: u32) -> String {
format!("the result of computation {}", input)
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx) = mpsc::channel(100);
tokio::spawn(async move {
for i in 0..10 {
let res = some_computation(i).await;
tx.send(res).await.unwrap();
}
});
while let Some(res) = rx.recv().await {
println!("got = {}", res);
}
# }
The argument to mpsc::channel is the channel capacity. This is the maximum
number of values that can be stored in the channel pending receipt at any
given time. Properly setting this value is key in implementing robust
programs as the channel capacity plays a critical part in handling back
pressure.
A common concurrency pattern for resource management is to spawn a task dedicated to managing that resource and using message passing between other tasks to interact with the resource. The resource may be anything that may not be concurrently used. Some examples include a socket and program state. For example, if multiple tasks need to send data over a single socket, spawn a task to manage the socket and use a channel to synchronize.
Example: sending data from many tasks over a single socket using message passing.
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::io::{self, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio::sync::mpsc;
#[tokio::main]
async fn main() -> io::Result<()> {
let mut socket = TcpStream::connect("www.example.com:1234").await?;
let (tx, mut rx) = mpsc::channel(100);
for _ in 0..10 {
// Each task needs its own `tx` handle. This is done by cloning the
// original handle.
let tx = tx.clone();
tokio::spawn(async move {
tx.send(&b"data to write"[..]).await.unwrap();
});
}
// The `rx` half of the channel returns `None` once **all** `tx` clones
// drop. To ensure `None` is returned, drop the handle owned by the
// current task. If this `tx` handle is not dropped, there will always
// be a single outstanding `tx` handle.
drop(tx);
while let Some(res) = rx.recv().await {
socket.write_all(res).await?;
}
Ok(())
}
# }
The mpsc and oneshot channels can be combined to provide a request /
response type synchronization pattern with a shared resource. A task is
spawned to synchronize a resource and waits on commands received on a
mpsc channel. Each command includes a oneshot Sender on which the
result of the command is sent.
Example: use a task to synchronize a u64 counter. Each task sends an
"fetch and increment" command. The counter value before the increment is
sent over the provided oneshot channel.
use tokio::sync::{oneshot, mpsc};
use Command::Increment;
enum Command {
Increment,
// Other commands can be added here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (cmd_tx, mut cmd_rx) = mpsc::channel::<(Command, oneshot::Sender<u64>)>(100);
// Spawn a task to manage the counter
tokio::spawn(async move {
let mut counter: u64 = 0;
while let Some((cmd, response)) = cmd_rx.recv().await {
match cmd {
Increment => {
let prev = counter;
counter += 1;
response.send(prev).unwrap();
}
}
}
});
let mut join_handles = vec![];
// Spawn tasks that will send the increment command.
for _ in 0..10 {
let cmd_tx = cmd_tx.clone();
join_handles.push(tokio::spawn(async move {
let (resp_tx, resp_rx) = oneshot::channel();
cmd_tx.send((Increment, resp_tx)).await.ok().unwrap();
let res = resp_rx.await.unwrap();
println!("previous value = {}", res);
}));
}
// Wait for all tasks to complete
for join_handle in join_handles.drain(..) {
join_handle.await.unwrap();
}
# }
broadcast channel
The broadcast channel supports sending many values from
many producers to many consumers. Each consumer will receive
each value. This channel can be used to implement "fan out" style
patterns common with pub / sub or "chat" systems.
This channel tends to be used less often than oneshot and mpsc but still
has its use cases.
This is also the channel you should use if you want to broadcast values from a single producer to many consumers. There is no dedicated spmc broadcast channel.
Basic usage
use tokio::sync::broadcast;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
tokio::spawn(async move {
assert_eq!(rx1.recv().await.unwrap(), 10);
assert_eq!(rx1.recv().await.unwrap(), 20);
});
tokio::spawn(async move {
assert_eq!(rx2.recv().await.unwrap(), 10);
assert_eq!(rx2.recv().await.unwrap(), 20);
});
tx.send(10).unwrap();
tx.send(20).unwrap();
# }
watch channel
The watch channel supports sending many values from many
producers to many consumers. However, only the most recent value is
stored in the channel. Consumers are notified when a new value is sent, but
there is no guarantee that consumers will see all values.
The watch channel is similar to a broadcast channel with capacity 1.
Use cases for the watch channel include broadcasting configuration
changes or signalling program state changes, such as transitioning to
shutdown.
Example: use a watch channel to notify tasks of configuration
changes. In this example, a configuration file is checked periodically. When
the file changes, the configuration changes are signalled to consumers.
use tokio::sync::watch;
use tokio::time::{self, Duration, Instant};
use std::io;
#[derive(Debug, Clone, Eq, PartialEq)]
struct Config {
timeout: Duration,
}
impl Config {
async fn load_from_file() -> io::Result<Config> {
// file loading and deserialization logic here
# Ok(Config { timeout: Duration::from_secs(1) })
}
}
async fn my_async_operation() {
// Do something here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
// Load initial configuration value
let mut config = Config::load_from_file().await.unwrap();
// Create the watch channel, initialized with the loaded configuration
let (tx, rx) = watch::channel(config.clone());
// Spawn a task to monitor the file.
tokio::spawn(async move {
loop {
// Wait 10 seconds between checks
time::sleep(Duration::from_secs(10)).await;
// Load the configuration file
let new_config = Config::load_from_file().await.unwrap();
// If the configuration changed, send the new config value
// on the watch channel.
if new_config != config {
tx.send(new_config.clone()).unwrap();
config = new_config;
}
}
});
let mut handles = vec![];
// Spawn tasks that runs the async operation for at most `timeout`. If
// the timeout elapses, restart the operation.
//
// The task simultaneously watches the `Config` for changes. When the
// timeout duration changes, the timeout is updated without restarting
// the in-flight operation.
for _ in 0..5 {
// Clone a config watch handle for use in this task
let mut rx = rx.clone();
let handle = tokio::spawn(async move {
// Start the initial operation and pin the future to the stack.
// Pinning to the stack is required to resume the operation
// across multiple calls to `select!`
let op = my_async_operation();
tokio::pin!(op);
// Get the initial config value
let mut conf = rx.borrow().clone();
let mut op_start = Instant::now();
let sleep = time::sleep_until(op_start + conf.timeout);
tokio::pin!(sleep);
loop {
tokio::select! {
_ = &mut sleep => {
// The operation elapsed. Restart it
op.set(my_async_operation());
// Track the new start time
op_start = Instant::now();
// Restart the timeout
sleep.set(time::sleep_until(op_start + conf.timeout));
}
_ = rx.changed() => {
conf = rx.borrow_and_update().clone();
// The configuration has been updated. Update the
// `sleep` using the new `timeout` value.
sleep.as_mut().reset(op_start + conf.timeout);
}
_ = &mut op => {
// The operation completed!
return
}
}
}
});
handles.push(handle);
}
for handle in handles.drain(..) {
handle.await.unwrap();
}
# }
State synchronization
The remaining synchronization primitives focus on synchronizing state.
These are asynchronous equivalents to versions provided by std. They
operate in a similar way as their std counterparts but will wait
asynchronously instead of blocking the thread.
-
BarrierEnsures multiple tasks will wait for each other to reach a point in the program, before continuing execution all together. -
MutexMutual Exclusion mechanism, which ensures that at most one thread at a time is able to access some data. -
[
Notify] Basic task notification.Notifysupports notifying a receiving task without sending data. In this case, the task wakes up and resumes processing. -
[
RwLock] Provides a mutual exclusion mechanism which allows multiple readers at the same time, while allowing only one writer at a time. In some cases, this can be more efficient than a mutex. -
[
Semaphore] Limits the amount of concurrency. A semaphore holds a number of permits, which tasks may request in order to enter a critical section. Semaphores are useful for implementing limiting or bounding of any kind.
Runtime compatibility
All synchronization primitives provided in this module are runtime agnostic. You can freely move them between different instances of the Tokio runtime or even use them from non-Tokio runtimes.
When used in a Tokio runtime, the synchronization primitives participate in cooperative scheduling to avoid starvation. This feature does not apply when used from non-Tokio runtimes.
As an exception, methods ending in _timeout are not runtime agnostic
because they require access to the Tokio timer. See the documentation of
each *_timeout method for more information on its use.
pub mod sync { /* ... */ }
Modules
Module futures
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
Named future types.
pub mod futures { /* ... */ }
Re-exports
Re-export Notified
pub use super::notify::Notified;
Re-export OwnedNotified
pub use super::notify::OwnedNotified;
Module broadcast
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
A multi-producer, multi-consumer broadcast queue. Each sent value is seen by all consumers.
A Sender is used to broadcast values to all connected Receiver
values. Sender handles are clone-able, allowing concurrent send and
receive actions. Sender and Receiver are both Send and Sync as
long as T is Send.
When a value is sent, all Receiver handles are notified and will
receive the value. The value is stored once inside the channel and cloned on
demand for each receiver. Once all receivers have received a clone of the
value, the value is released from the channel.
A channel is created by calling channel, specifying the maximum number
of messages the channel can retain at any given time.
New Receiver handles are created by calling Sender::subscribe. The
returned Receiver will receive values sent after the call to
subscribe.
This channel is also suitable for the single-producer multi-consumer use-case, where a single sender broadcasts values to many receivers.
Lagging
As sent messages must be retained until all Receiver handles receive
a clone, broadcast channels are susceptible to the "slow receiver" problem.
In this case, all but one receiver are able to receive values at the rate
they are sent. Because one receiver is stalled, the channel starts to fill
up.
This broadcast channel implementation handles this case by setting a hard
upper bound on the number of values the channel may retain at any given
time. This upper bound is passed to the channel function as an argument.
If a value is sent when the channel is at capacity, the oldest value
currently held by the channel is released. This frees up space for the new
value. Any receiver that has not yet seen the released value will return
RecvError::Lagged the next time recv is called.
Once RecvError::Lagged is returned, the lagging receiver's position is
updated to the oldest value contained by the channel. The next call to
recv will return this value.
This behavior enables a receiver to detect when it has lagged so far behind that data has been dropped. The caller may decide how to respond to this: either by aborting its task or by tolerating lost messages and resuming consumption of the channel.
Closing
When all Sender handles have been dropped, no new values may be
sent. At this point, the channel is "closed". Once a receiver has received
all values retained by the channel, the next call to recv will return
with RecvError::Closed.
When a Receiver handle is dropped, any messages not read by the receiver
will be marked as read. If this receiver was the only one not to have read
that message, the message will be dropped at this point.
Examples
Basic usage
use tokio::sync::broadcast;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
tokio::spawn(async move {
assert_eq!(rx1.recv().await.unwrap(), 10);
assert_eq!(rx1.recv().await.unwrap(), 20);
});
tokio::spawn(async move {
assert_eq!(rx2.recv().await.unwrap(), 10);
assert_eq!(rx2.recv().await.unwrap(), 20);
});
tx.send(10).unwrap();
tx.send(20).unwrap();
# }
Handling lag
use tokio::sync::broadcast;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx) = broadcast::channel(2);
tx.send(10).unwrap();
tx.send(20).unwrap();
tx.send(30).unwrap();
// The receiver lagged behind
assert!(rx.recv().await.is_err());
// At this point, we can abort or continue with lost messages
assert_eq!(20, rx.recv().await.unwrap());
assert_eq!(30, rx.recv().await.unwrap());
# }
pub mod broadcast { /* ... */ }
Modules
Module error
Broadcast error types
pub mod error { /* ... */ }
Types
Struct SendError
Error returned by the send function on a Sender.
A send operation can only fail if there are no active receivers, implying that the message could never be received. The error contains the message being sent as a payload so it can be recovered.
pub struct SendError<T>(pub T);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum RecvError
An error returned from the recv function on a Receiver.
pub enum RecvError {
Closed,
Lagged(u64),
}
Variants
Closed
There are no more active senders implying no further messages will ever be sent.
Lagged
The receiver lagged too far behind. Attempting to receive again will return the oldest message still retained by the channel.
Includes the number of skipped messages.
Fields:
| Index | Type | Documentation |
|---|---|---|
| 0 | u64 |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> RecvError { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &RecvError) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum TryRecvError
An error returned from the try_recv function on a Receiver.
pub enum TryRecvError {
Empty,
Closed,
Lagged(u64),
}
Variants
Empty
The channel is currently empty. There are still active
Sender handles, so data may yet become available.
Closed
There are no more active senders implying no further messages will ever be sent.
Lagged
The receiver lagged too far behind and has been forcibly disconnected. Attempting to receive again will return the oldest message still retained by the channel.
Includes the number of skipped messages.
Fields:
| Index | Type | Documentation |
|---|---|---|
| 0 | u64 |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> TryRecvError { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &TryRecvError) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Types
Struct Sender
Sending-half of the broadcast channel.
May be used from many threads. Messages can be sent with
[send][Sender::send].
Examples
use tokio::sync::broadcast;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
tokio::spawn(async move {
assert_eq!(rx1.recv().await.unwrap(), 10);
assert_eq!(rx1.recv().await.unwrap(), 20);
});
tokio::spawn(async move {
assert_eq!(rx2.recv().await.unwrap(), 10);
assert_eq!(rx2.recv().await.unwrap(), 20);
});
tx.send(10).unwrap();
tx.send(20).unwrap();
# }
pub struct Sender<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new(capacity: usize) -> Self { /* ... */ }Creates the sending-half of the
broadcastchannel. -
pub fn send(self: &Self, value: T) -> Result<usize, SendError<T>> { /* ... */ }Attempts to send a value to all active
Receiverhandles, returning -
pub fn subscribe(self: &Self) -> Receiver<T> { /* ... */ }Creates a new
Receiverhandle that will receive values sent after -
pub fn downgrade(self: &Self) -> WeakSender<T> { /* ... */ }Converts the
Senderto a [WeakSender] that does not count -
pub fn len(self: &Self) -> usize { /* ... */ }Returns the number of queued values.
-
pub fn is_empty(self: &Self) -> bool { /* ... */ }Returns true if there are no queued values.
-
pub fn receiver_count(self: &Self) -> usize { /* ... */ }Returns the number of active receivers.
-
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }Returns
trueif senders belong to the same channel. -
pub async fn closed(self: &Self) { /* ... */ }A future which completes when the number of [Receiver]s subscribed to this
Senderreaches -
pub fn strong_count(self: &Self) -> usize { /* ... */ }Returns the number of
Senderhandles. -
pub fn weak_count(self: &Self) -> usize { /* ... */ }Returns the number of [
WeakSender] handles.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> Sender<T> { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct WeakSender
A sender that does not prevent the channel from being closed.
If all Sender instances of a channel were dropped and only WeakSender
instances remain, the channel is closed.
In order to send messages, the WeakSender needs to be upgraded using
WeakSender::upgrade, which returns Option<Sender>. It returns None
if all Senders have been dropped, and otherwise it returns a Sender.
Examples
use tokio::sync::broadcast::channel;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, _rx) = channel::<i32>(15);
let tx_weak = tx.downgrade();
// Upgrading will succeed because `tx` still exists.
assert!(tx_weak.upgrade().is_some());
// If we drop `tx`, then it will fail.
drop(tx);
assert!(tx_weak.clone().upgrade().is_none());
# }
pub struct WeakSender<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn upgrade(self: &Self) -> Option<Sender<T>> { /* ... */ }Tries to convert a
WeakSenderinto aSender. -
pub fn strong_count(self: &Self) -> usize { /* ... */ }Returns the number of
Senderhandles. -
pub fn weak_count(self: &Self) -> usize { /* ... */ }Returns the number of [
WeakSender] handles.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> WeakSender<T> { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Receiver
Receiving-half of the broadcast channel.
Must not be used concurrently. Messages may be retrieved using
[recv][Receiver::recv].
To turn this receiver into a Stream, you can use the BroadcastStream
wrapper.
Examples
use tokio::sync::broadcast;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
tokio::spawn(async move {
assert_eq!(rx1.recv().await.unwrap(), 10);
assert_eq!(rx1.recv().await.unwrap(), 20);
});
tokio::spawn(async move {
assert_eq!(rx2.recv().await.unwrap(), 10);
assert_eq!(rx2.recv().await.unwrap(), 20);
});
tx.send(10).unwrap();
tx.send(20).unwrap();
# }
pub struct Receiver<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn len(self: &Self) -> usize { /* ... */ }Returns the number of messages that were sent into the channel and that
-
pub fn is_empty(self: &Self) -> bool { /* ... */ }Returns true if there aren't any messages in the channel that the
Receiver -
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }Returns
trueif receivers belong to the same channel. -
pub fn sender_strong_count(self: &Self) -> usize { /* ... */ }Returns the number of
Senderhandles. -
pub fn sender_weak_count(self: &Self) -> usize { /* ... */ }Returns the number of [
WeakSender] handles. -
pub fn is_closed(self: &Self) -> bool { /* ... */ }Checks if a channel is closed.
-
pub fn resubscribe(self: &Self) -> Self { /* ... */ }Re-subscribes to the channel starting from the current tail element.
-
pub async fn recv(self: &mut Self) -> Result<T, RecvError> { /* ... */ }Receives the next value for this receiver.
-
pub fn try_recv(self: &mut Self) -> Result<T, TryRecvError> { /* ... */ }Attempts to return a pending value on this receiver without awaiting.
-
pub fn blocking_recv(self: &mut Self) -> Result<T, RecvError> { /* ... */ }Blocking receive to call outside of asynchronous contexts.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function channel
Attributes:
Other("#[attr = TrackCaller]")
Create a bounded, multi-producer, multi-consumer channel where each sent value is broadcasted to all active receivers.
Note: The actual capacity may be greater than the provided capacity.
All data sent on Sender will become available on every active
Receiver in the same order as it was sent.
The Sender can be cloned to send to the same channel from multiple
points in the process or it can be used concurrently from an Arc. New
Receiver handles are created by calling Sender::subscribe.
If all Receiver handles are dropped, the send method will return a
SendError. Similarly, if all Sender handles are dropped, the recv
method will return a RecvError.
Examples
use tokio::sync::broadcast;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
tokio::spawn(async move {
assert_eq!(rx1.recv().await.unwrap(), 10);
assert_eq!(rx1.recv().await.unwrap(), 20);
});
tokio::spawn(async move {
assert_eq!(rx2.recv().await.unwrap(), 10);
assert_eq!(rx2.recv().await.unwrap(), 20);
});
tx.send(10).unwrap();
tx.send(20).unwrap();
# }
Panics
This will panic if capacity is equal to 0.
This pre-allocates space for capacity messages. Allocation failure may result in a panic or
an allocation error.
pub fn channel<T: Clone>(capacity: usize) -> (Sender<T>, Receiver<T>) { /* ... */ }
Module mpsc
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")Other("#[<cfg_attr>(not(feature = \"sync\"), allow(dead_code, unreachable_pub))]")
A multi-producer, single-consumer queue for sending values between asynchronous tasks.
This module provides two variants of the channel: bounded and unbounded. The
bounded variant has a limit on the number of messages that the channel can
store, and if this limit is reached, trying to send another message will
wait until a message is received from the channel. An unbounded channel has
an infinite capacity, so the send method will always complete immediately.
This makes the UnboundedSender usable from both synchronous and
asynchronous code.
Similar to the mpsc channels provided by std, the channel constructor
functions provide separate send and receive handles, Sender and
Receiver for the bounded channel, UnboundedSender and
UnboundedReceiver for the unbounded channel. If there is no message to read,
the current task will be notified when a new value is sent. Sender and
UnboundedSender allow sending values into the channel. If the bounded
channel is at capacity, the send is rejected and the task will be notified
when additional capacity is available. In other words, the channel provides
backpressure.
This channel is also suitable for the single-producer single-consumer use-case. (Unless you only need to send one message, in which case you should use the oneshot channel.)
Disconnection
When all Sender handles have been dropped, it is no longer
possible to send values into the channel. This is considered the termination
event of the stream. As such, Receiver::poll returns Ok(Ready(None)).
If the Receiver handle is dropped, then messages can no longer
be read out of the channel. In this case, all further attempts to send will
result in an error. Additionally, all unread messages will be drained from the
channel and dropped.
Clean Shutdown
When the Receiver is dropped, it is possible for unprocessed messages to
remain in the channel. Instead, it is usually desirable to perform a "clean"
shutdown. To do this, the receiver first calls close, which will prevent
any further messages to be sent into the channel. Then, the receiver
consumes the channel to completion, at which point the receiver can be
dropped.
Communicating between sync and async code
When you want to communicate between synchronous and asynchronous code, there are two situations to consider:
Bounded channel: If you need a bounded channel, you should use a bounded
Tokio mpsc channel for both directions of communication. Instead of calling
the async send or recv methods, in
synchronous code you will need to use the blocking_send or
blocking_recv methods.
Unbounded channel: You should use the kind of channel that matches where
the receiver is. So for sending a message from async to sync, you should
use the standard library unbounded channel or
crossbeam. Similarly, for sending a message from sync
to async, you should use an unbounded Tokio mpsc channel.
Please be aware that the above remarks were written with the mpsc channel
in mind, but they can also be generalized to other kinds of channels. In
general, any channel method that isn't marked async can be called anywhere,
including outside of the runtime. For example, sending a message on a
oneshot channel from outside the runtime is perfectly fine.
Multiple runtimes
The mpsc channel is runtime agnostic. You can freely move it between
different instances of the Tokio runtime or even use it from non-Tokio
runtimes.
When used in a Tokio runtime, it participates in cooperative scheduling to avoid starvation. This feature does not apply when used from non-Tokio runtimes.
As an exception, methods ending in _timeout are not runtime agnostic
because they require access to the Tokio timer. See the documentation of
each *_timeout method for more information on its use.
Allocation behavior
The mpsc channel stores elements in blocks. Blocks are organized in a linked list. Sending pushes new elements onto the block at the front of the list, and receiving pops them off the one at the back. A block can hold 32 messages on a 64-bit target and 16 messages on a 32-bit target. This number is independent of channel and message size. Each block also stores 4 pointer-sized values for bookkeeping (so on a 64-bit machine, each message has 1 byte of overhead).
When all values in a block have been received, it becomes empty. It will then be freed, unless the channel's first block (where newly-sent elements are being stored) has no next block. In that case, the empty block is reused as the next block.
pub mod mpsc { /* ... */ }
Modules
Module error
Channel error types.
pub mod error { /* ... */ }
Types
Struct SendError
Error returned by the Sender.
pub struct SendError<T>(pub T);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> SendError<T> { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
fn from(t: T) -> T { /* ... */ }Returns the argument unchanged.
-
fn from(src: SendError<T>) -> TrySendError<T> { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &SendError<T>) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum TrySendError
This enumeration is the list of the possible error outcomes for the
try_send method.
pub enum TrySendError<T> {
Full(T),
Closed(T),
}
Variants
Full
The data could not be sent on the channel because the channel is currently full and sending would require blocking.
Fields:
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Closed
The receive half of the channel was explicitly closed or has been dropped.
Fields:
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Implementations
Methods
-
Consume the
pub fn into_inner(self: Self) -> T { /* ... */ }TrySendError, returning the unsent value.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> TrySendError<T> { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
fn from(t: T) -> T { /* ... */ }Returns the argument unchanged.
-
fn from(src: SendError<T>) -> TrySendError<T> { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &TrySendError<T>) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum TryRecvError
Error returned by try_recv.
pub enum TryRecvError {
Empty,
Disconnected,
}
Variants
Empty
This channel is currently empty, but the Sender(s) have not yet disconnected, so data may yet become available.
Disconnected
The channel's sending half has become disconnected, and there will never be any more data received on it.
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> TryRecvError { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &TryRecvError) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum SendTimeoutError
Attributes:
Other("#[<cfg>(feature = \"time\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"time\")))]")Other("#[doc(cfg(feature = \"time\"))]")
Error returned by Sender::send_timeout].
pub enum SendTimeoutError<T> {
Timeout(T),
Closed(T),
}
Variants
Timeout
The data could not be sent on the channel because the channel is full, and the timeout to send has elapsed.
Fields:
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Closed
The receive half of the channel was explicitly closed or has been dropped.
Fields:
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Implementations
Methods
-
Consume the
pub fn into_inner(self: Self) -> T { /* ... */ }SendTimeoutError, returning the unsent value.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> SendTimeoutError<T> { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &SendTimeoutError<T>) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Re-exports
Re-export channel
pub use self::bounded::channel;
Re-export OwnedPermit
pub use self::bounded::OwnedPermit;
Re-export Permit
pub use self::bounded::Permit;
Re-export PermitIterator
pub use self::bounded::PermitIterator;
Re-export Receiver
pub use self::bounded::Receiver;
Re-export Sender
pub use self::bounded::Sender;
Re-export WeakSender
pub use self::bounded::WeakSender;
Re-export unbounded_channel
pub use self::unbounded::unbounded_channel;
Re-export UnboundedReceiver
pub use self::unbounded::UnboundedReceiver;
Re-export UnboundedSender
pub use self::unbounded::UnboundedSender;
Re-export WeakUnboundedSender
pub use self::unbounded::WeakUnboundedSender;
Module oneshot
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")Other("#[<cfg_attr>(not(feature = \"sync\"), allow(dead_code, unreachable_pub))]")
A one-shot channel is used for sending a single message between
asynchronous tasks. The channel function is used to create a
Sender and Receiver handle pair that form the channel.
The Sender handle is used by the producer to send the value.
The Receiver handle is used by the consumer to receive the value.
Each handle can be used on separate tasks.
Since the send method is not async, it can be used anywhere. This includes
sending between two runtimes, and using it from non-async code.
If the Receiver is closed before receiving a message which has already
been sent, the message will remain in the channel until the receiver is
dropped, at which point the message will be dropped immediately.
Examples
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
if let Err(_) = tx.send(3) {
println!("the receiver dropped");
}
});
match rx.await {
Ok(v) => println!("got = {:?}", v),
Err(_) => println!("the sender dropped"),
}
# }
If the sender is dropped without sending, the receiver will fail with
[error::RecvError]:
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel::<u32>();
tokio::spawn(async move {
drop(tx);
});
match rx.await {
Ok(_) => panic!("This doesn't happen"),
Err(_) => println!("the sender dropped"),
}
# }
To use a oneshot channel in a tokio::select! loop, add &mut in front of
the channel.
use tokio::sync::oneshot;
use tokio::time::{interval, sleep, Duration};
# #[tokio::main(flavor = "current_thread")]
# async fn _doc() {}
# #[tokio::main(flavor = "current_thread", start_paused = true)]
# async fn main() {
let (send, mut recv) = oneshot::channel();
let mut interval = interval(Duration::from_millis(100));
# let handle =
tokio::spawn(async move {
sleep(Duration::from_secs(1)).await;
send.send("shut down").unwrap();
});
loop {
tokio::select! {
_ = interval.tick() => println!("Another 100ms"),
msg = &mut recv => {
println!("Got message: {}", msg.unwrap());
break;
}
}
}
# handle.await.unwrap();
# }
To use a Sender from a destructor, put it in an Option and call
Option::take.
use tokio::sync::oneshot;
struct SendOnDrop {
sender: Option<oneshot::Sender<&'static str>>,
}
impl Drop for SendOnDrop {
fn drop(&mut self) {
if let Some(sender) = self.sender.take() {
// Using `let _ =` to ignore send errors.
let _ = sender.send("I got dropped!");
}
}
}
# #[tokio::main(flavor = "current_thread")]
# async fn _doc() {}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (send, recv) = oneshot::channel();
let send_on_drop = SendOnDrop { sender: Some(send) };
drop(send_on_drop);
assert_eq!(recv.await, Ok("I got dropped!"));
# }
pub mod oneshot { /* ... */ }
Modules
Module error
Oneshot error types.
pub mod error { /* ... */ }
Types
Struct RecvError
Error returned by the Future implementation for Receiver.
This error is returned by the receiver when the sender is dropped without sending.
pub struct RecvError(/* private field */);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | private |
Private field |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> RecvError { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &RecvError) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Enum TryRecvError
Error returned by the try_recv function on Receiver.
pub enum TryRecvError {
Empty,
Closed,
}
Variants
Empty
The send half of the channel has not yet sent a value.
Closed
The send half of the channel was dropped without sending a value.
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> TryRecvError { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &TryRecvError) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Types
Struct Sender
Sends a value to the associated Receiver.
A pair of both a Sender and a Receiver are created by the
channel function.
Examples
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
if let Err(_) = tx.send(3) {
println!("the receiver dropped");
}
});
match rx.await {
Ok(v) => println!("got = {:?}", v),
Err(_) => println!("the sender dropped"),
}
# }
If the sender is dropped without sending, the receiver will fail with
[error::RecvError]:
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel::<u32>();
tokio::spawn(async move {
drop(tx);
});
match rx.await {
Ok(_) => panic!("This doesn't happen"),
Err(_) => println!("the sender dropped"),
}
# }
To use a Sender from a destructor, put it in an Option and call
Option::take.
use tokio::sync::oneshot;
struct SendOnDrop {
sender: Option<oneshot::Sender<&'static str>>,
}
impl Drop for SendOnDrop {
fn drop(&mut self) {
if let Some(sender) = self.sender.take() {
// Using `let _ =` to ignore send errors.
let _ = sender.send("I got dropped!");
}
}
}
# #[tokio::main(flavor = "current_thread")]
# async fn _doc() {}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (send, recv) = oneshot::channel();
let send_on_drop = SendOnDrop { sender: Some(send) };
drop(send_on_drop);
assert_eq!(recv.await, Ok("I got dropped!"));
# }
pub struct Sender<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn send(self: Self, t: T) -> Result<(), T> { /* ... */ }Attempts to send a value on this channel, returning it back if it could
-
pub async fn closed(self: &mut Self) { /* ... */ }Waits for the associated
Receiverhandle to close. -
pub fn is_closed(self: &Self) -> bool { /* ... */ }Returns
trueif the associatedReceiverhandle has been dropped. -
pub fn poll_closed(self: &mut Self, cx: &mut Context<''_>) -> Poll<()> { /* ... */ }Checks whether the
oneshotchannel has been closed, and if not, schedules the
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Receiver
Receives a value from the associated Sender.
A pair of both a Sender and a Receiver are created by the
channel function.
This channel has no recv method because the receiver itself implements the
Future trait. To receive a Result<T, [error::RecvError]>, .await the Receiver object directly.
The poll method on the Future trait is allowed to spuriously return
Poll::Pending even if the message has been sent. If such a spurious
failure happens, then the caller will be woken when the spurious failure has
been resolved so that the caller can attempt to receive the message again.
Note that receiving such a wakeup does not guarantee that the next call will
succeed — it could fail with another spurious failure. (A spurious failure
does not mean that the message is lost. It is just delayed.)
Examples
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
if let Err(_) = tx.send(3) {
println!("the receiver dropped");
}
});
match rx.await {
Ok(v) => println!("got = {:?}", v),
Err(_) => println!("the sender dropped"),
}
# }
If the sender is dropped without sending, the receiver will fail with
[error::RecvError]:
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel::<u32>();
tokio::spawn(async move {
drop(tx);
});
match rx.await {
Ok(_) => panic!("This doesn't happen"),
Err(_) => println!("the sender dropped"),
}
# }
To use a Receiver in a tokio::select! loop, add &mut in front of the
channel.
use tokio::sync::oneshot;
use tokio::time::{interval, sleep, Duration};
# #[tokio::main(flavor = "current_thread")]
# async fn _doc() {}
# #[tokio::main(flavor = "current_thread", start_paused = true)]
# async fn main() {
let (send, mut recv) = oneshot::channel();
let mut interval = interval(Duration::from_millis(100));
# let handle =
tokio::spawn(async move {
sleep(Duration::from_secs(1)).await;
send.send("shut down").unwrap();
});
loop {
tokio::select! {
_ = interval.tick() => println!("Another 100ms"),
msg = &mut recv => {
println!("Got message: {}", msg.unwrap());
break;
}
}
}
# handle.await.unwrap();
# }
pub struct Receiver<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn close(self: &mut Self) { /* ... */ }Prevents the associated
Senderhandle from sending a value. -
pub fn is_terminated(self: &Self) -> bool { /* ... */ }Checks if this receiver is terminated.
-
pub fn is_empty(self: &Self) -> bool { /* ... */ }Checks if a channel is empty.
-
pub fn try_recv(self: &mut Self) -> Result<T, TryRecvError> { /* ... */ }Attempts to receive a value.
-
pub fn blocking_recv(self: Self) -> Result<T, RecvError> { /* ... */ }Blocking receive to call outside of asynchronous contexts.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Future
-
fn poll(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<<Self as >::Output> { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
IntoFuture
-
fn into_future(self: Self) -> <F as IntoFuture>::IntoFuture { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function channel
Attributes:
Other("#[attr = TrackCaller]")
Creates a new one-shot channel for sending single values across asynchronous tasks.
The function returns separate "send" and "receive" handles. The Sender
handle is used by the producer to send the value. The Receiver handle is
used by the consumer to receive the value.
Each handle can be used on separate tasks.
Examples
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, rx) = oneshot::channel();
tokio::spawn(async move {
if let Err(_) = tx.send(3) {
println!("the receiver dropped");
}
});
match rx.await {
Ok(v) => println!("got = {:?}", v),
Err(_) => println!("the sender dropped"),
}
# }
pub fn channel<T>() -> (Sender<T>, Receiver<T>) { /* ... */ }
Module watch
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")Other("#[<cfg_attr>(not(feature = \"sync\"), allow(dead_code, unreachable_pub))]")
A multi-producer, multi-consumer channel that only retains the last sent value.
This channel is useful for watching for changes to a value from multiple points in the code base, for example, changes to configuration values.
Usage
channel returns a Sender / Receiver pair. These are the producer
and consumer halves of the channel. The channel is created with an initial
value.
Each Receiver independently tracks the last value seen by its caller.
To access the current value stored in the channel and mark it as seen
by a given Receiver, use Receiver::borrow_and_update().
To access the current value without marking it as seen, use
Receiver::borrow(). (If the value has already been marked seen,
Receiver::borrow() is equivalent to Receiver::borrow_and_update().)
For more information on when to use these methods, see here.
Change notifications
The Receiver half provides an asynchronous changed method. This
method is ready when a new, unseen value is sent via the Sender half.
Receiver::changed()returns:Ok(())on receiving a new value.Err(RecvError)if the channel has been closed AND the current value is seen.
- If the current value is unseen when calling
changed, thenchangedwill return immediately. If the current value is seen, then it will sleep until either a new message is sent via theSenderhalf, or theSenderis dropped. - On completion, the
changedmethod marks the new value as seen. - At creation, the initial value is considered seen. In other words,
Receiver::changed()will not return until a subsequent value is sent. - New
Receiverinstances can be created withSender::subscribe(). The current value at the time theReceiveris created is considered seen.
changed versus has_changed
The Receiver half provides two methods for checking for changes
in the channel, has_changed and changed.
-
has_changedis a synchronous method that checks whether the current value is seen or not and returns a boolean. This method does not mark the value as seen. -
changedis an asynchronous method that will return once an unseen value is in the channel. This method does mark the value as seen.
Note there are two behavioral differences on when these two methods return an error.
has_changederrors if and only if the channel is closed.changederrors if the channel has been closed AND the current value is seen.
See the example below that shows how these methods have different fallibility.
borrow_and_update versus borrow
If the receiver intends to await notifications from changed in a loop,
Receiver::borrow_and_update() should be preferred over
Receiver::borrow(). This avoids a potential race where a new value is
sent between changed being ready and the value being read. (If
Receiver::borrow() is used, the loop may run twice with the same value.)
If the receiver is only interested in the current value, and does not intend
to wait for changes, then Receiver::borrow() can be used. It may be more
convenient to use borrow since it's an &self
method---borrow_and_update requires &mut self.
Examples
The following example prints hello! world! .
use tokio::sync::watch;
use tokio::time::{Duration, sleep};
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
let (tx, mut rx) = watch::channel("hello");
tokio::spawn(async move {
// Use the equivalent of a "do-while" loop so the initial value is
// processed before awaiting the `changed()` future.
loop {
println!("{}! ", *rx.borrow_and_update());
if rx.changed().await.is_err() {
break;
}
}
});
sleep(Duration::from_millis(100)).await;
tx.send("world")?;
# Ok(())
# }
Difference on fallibility of changed versus has_changed.
use tokio::sync::watch;
#[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx, mut rx) = watch::channel("hello");
tx.send("goodbye").unwrap();
drop(tx);
// `has_changed` does not mark the value as seen and errors
// since the channel is closed.
assert!(rx.has_changed().is_err());
// `changed` returns Ok since the value is not already marked as seen
// even if the channel is closed.
assert!(rx.changed().await.is_ok());
// The `changed` call above marks the value as seen.
// The next `changed` call now returns an error as the channel is closed
// AND the current value is seen.
assert!(rx.changed().await.is_err());
# }
Closing
Sender::is_closed and Sender::closed allow the producer to detect
when all Receiver handles have been dropped. This indicates that there
is no further interest in the values being produced and work can be stopped.
The value in the channel will not be dropped until all senders and all receivers have been dropped.
Thread safety
Both Sender and Receiver are thread safe. They can be moved to other
threads and can be used in a concurrent environment. Clones of Receiver
handles may be moved to separate threads and also used concurrently.
pub mod watch { /* ... */ }
Modules
Module error
Watch error types.
pub mod error { /* ... */ }
Types
Struct SendError
Error produced when sending a value fails.
pub struct SendError<T>(pub T);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | T |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> SendError<T> { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &SendError<T>) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct RecvError
Error produced when receiving a change notification.
pub struct RecvError(/* private field */);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | private |
Private field |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> RecvError { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Types
Struct Receiver
Receives values from the associated Sender.
Instances are created by the channel function.
To turn this receiver into a Stream, you can use the WatchStream
wrapper.
pub struct Receiver<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn borrow(self: &Self) -> Ref<''_, T> { /* ... */ }Returns a reference to the most recently sent value.
-
pub fn borrow_and_update(self: &mut Self) -> Ref<''_, T> { /* ... */ }Returns a reference to the most recently sent value and marks that value
-
pub fn has_changed(self: &Self) -> Result<bool, error::RecvError> { /* ... */ }Checks if this channel contains a message that this receiver has not yet
-
pub fn mark_changed(self: &mut Self) { /* ... */ }Marks the state as changed.
-
pub fn mark_unchanged(self: &mut Self) { /* ... */ }Marks the state as unchanged.
-
pub async fn changed(self: &mut Self) -> Result<(), error::RecvError> { /* ... */ }Waits for a change notification, then marks the current value as seen.
-
pub async fn wait_for</* synthetic */ impl FnMut(&T) -> bool: FnMut(&T) -> bool>(self: &mut Self, f: impl FnMut(&T) -> bool) -> Result<Ref<''_, T>, error::RecvError> { /* ... */ }Waits for a value that satisfies the provided condition.
-
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }Returns
trueif receivers belong to the same channel.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> Self { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Sender
Sends values to the associated Receiver.
Instances are created by the channel function.
pub struct Sender<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new(init: T) -> Self { /* ... */ }Creates the sending-half of the
watchchannel. -
pub fn send(self: &Self, value: T) -> Result<(), error::SendError<T>> { /* ... */ }Sends a new value via the channel, notifying all receivers.
-
pub fn send_modify<F>(self: &Self, modify: F)
where F: FnOnce(&mut T) { /* ... */ }
Modifies the watched value **unconditionally** in-place,
- ```rust
pub fn send_if_modified<F>(self: &Self, modify: F) -> bool
where
F: FnOnce(&mut T) -> bool { /* ... */ }
Modifies the watched value conditionally in-place,
-
pub fn send_replace(self: &Self, value: T) -> T { /* ... */ }Sends a new value via the channel, notifying all receivers and returning
-
pub fn borrow(self: &Self) -> Ref<''_, T> { /* ... */ }Returns a reference to the most recently sent value
-
pub fn is_closed(self: &Self) -> bool { /* ... */ }Checks if the channel has been closed. This happens when all receivers
-
pub async fn closed(self: &Self) { /* ... */ }Completes when all receivers have dropped.
-
pub fn subscribe(self: &Self) -> Receiver<T> { /* ... */ }Creates a new
Receiverconnected to thisSender. -
pub fn receiver_count(self: &Self) -> usize { /* ... */ }Returns the number of receivers that currently exist.
-
pub fn sender_count(self: &Self) -> usize { /* ... */ }Returns the number of senders that currently exist.
-
pub fn same_channel(self: &Self, other: &Self) -> bool { /* ... */ }Returns
trueif senders belong to the same channel.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> Self { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Default
-
fn default() -> Self { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Ref
Returns a reference to the inner value.
Outstanding borrows hold a read lock on the inner value. This means that
long-lived borrows could cause the producer half to block. It is recommended
to keep the borrow as short-lived as possible. Additionally, if you are
running in an environment that allows !Send futures, you must ensure that
the returned Ref type is never held alive across an .await point,
otherwise, it can lead to a deadlock.
The priority policy of the lock is dependent on the underlying lock
implementation, and this type does not guarantee that any particular policy
will be used. In particular, a producer which is waiting to acquire the lock
in send might or might not block concurrent calls to borrow, e.g.:
Potential deadlock example
// Task 1 (on thread A) | // Task 2 (on thread B)
let _ref1 = rx.borrow(); |
| // will block
| let _ = tx.send(());
// may deadlock |
let _ref2 = rx.borrow(); |
pub struct Ref<''a, T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
Indicates if the borrowed value is considered as changed since the last
pub fn has_changed(self: &Self) -> bool { /* ... */ }
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Deref
-
fn deref(self: &Self) -> &T { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
Receiver
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function channel
Creates a new watch channel, returning the "send" and "receive" handles.
All values sent by Sender will become visible to the Receiver handles.
Only the last value sent is made available to the Receiver half. All
intermediate values are dropped.
Examples
The following example prints hello! world! .
use tokio::sync::watch;
use tokio::time::{Duration, sleep};
# async fn dox() -> Result<(), Box<dyn std::error::Error>> {
let (tx, mut rx) = watch::channel("hello");
tokio::spawn(async move {
// Use the equivalent of a "do-while" loop so the initial value is
// processed before awaiting the `changed()` future.
loop {
println!("{}! ", *rx.borrow_and_update());
if rx.changed().await.is_err() {
break;
}
}
});
sleep(Duration::from_millis(100)).await;
tx.send("world")?;
# Ok(())
# }
pub fn channel<T>(init: T) -> (Sender<T>, Receiver<T>) { /* ... */ }
Re-exports
Re-export Barrier
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use barrier::Barrier;
Re-export BarrierWaitResult
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use barrier::BarrierWaitResult;
Re-export Mutex
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use mutex::Mutex;
Re-export MutexGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use mutex::MutexGuard;
Re-export TryLockError
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use mutex::TryLockError;
Re-export OwnedMutexGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use mutex::OwnedMutexGuard;
Re-export MappedMutexGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use mutex::MappedMutexGuard;
Re-export OwnedMappedMutexGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use mutex::OwnedMappedMutexGuard;
Re-export Notify
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use notify::Notify;
Re-export AcquireError
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use batch_semaphore::AcquireError;
Re-export TryAcquireError
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use batch_semaphore::TryAcquireError;
Re-export Semaphore
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use semaphore::Semaphore;
Re-export SemaphorePermit
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use semaphore::SemaphorePermit;
Re-export OwnedSemaphorePermit
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use semaphore::OwnedSemaphorePermit;
Re-export RwLock
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::RwLock;
Re-export OwnedRwLockReadGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::owned_read_guard::OwnedRwLockReadGuard;
Re-export OwnedRwLockWriteGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::owned_write_guard::OwnedRwLockWriteGuard;
Re-export OwnedRwLockMappedWriteGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::owned_write_guard_mapped::OwnedRwLockMappedWriteGuard;
Re-export RwLockReadGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::read_guard::RwLockReadGuard;
Re-export RwLockWriteGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::write_guard::RwLockWriteGuard;
Re-export RwLockMappedWriteGuard
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use rwlock::write_guard_mapped::RwLockMappedWriteGuard;
Re-export OnceCell
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use self::once_cell::OnceCell;
Re-export SetError
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use self::once_cell::SetError;
Re-export SetOnce
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use self::set_once::SetOnce;
Re-export SetOnceError
Attributes:
Other("#[<cfg>(feature = \"sync\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"sync\")))]")Other("#[doc(cfg(feature = \"sync\"))]")
pub use self::set_once::SetOnceError;
Module task
Asynchronous green-threads.
What are Tasks?
A task is a light weight, non-blocking unit of execution. A task is similar to an OS thread, but rather than being managed by the OS scheduler, they are managed by the Tokio runtime. Another name for this general pattern is green threads. If you are familiar with Go's goroutines, Kotlin's coroutines, or Erlang's processes, you can think of Tokio's tasks as something similar.
Key points about tasks include:
-
Tasks are light weight. Because tasks are scheduled by the Tokio runtime rather than the operating system, creating new tasks or switching between tasks does not require a context switch and has fairly low overhead. Creating, running, and destroying large numbers of tasks is quite cheap, especially compared to OS threads.
-
Tasks are scheduled cooperatively. Most operating systems implement preemptive multitasking. This is a scheduling technique where the operating system allows each thread to run for a period of time, and then preempts it, temporarily pausing that thread and switching to another. Tasks, on the other hand, implement cooperative multitasking. In cooperative multitasking, a task is allowed to run until it yields, indicating to the Tokio runtime's scheduler that it cannot currently continue executing. When a task yields, the Tokio runtime switches to executing the next task.
-
Tasks are non-blocking. Typically, when an OS thread performs I/O or must synchronize with another thread, it blocks, allowing the OS to schedule another thread. When a task cannot continue executing, it must yield instead, allowing the Tokio runtime to schedule another task. Tasks should generally not perform system calls or other operations that could block a thread, as this would prevent other tasks running on the same thread from executing as well. Instead, this module provides APIs for running blocking operations in an asynchronous context.
Working with Tasks
This module provides the following APIs for working with tasks:
Spawning
Perhaps the most important function in this module is task::spawn. This
function can be thought of as an async equivalent to the standard library's
thread::spawn. It takes an async block or other
future, and creates a new task to run that work concurrently:
use tokio::task;
# async fn doc() {
task::spawn(async {
// perform some work here...
});
# }
Like std::thread::spawn, task::spawn returns a JoinHandle struct.
A JoinHandle is itself a future which may be used to await the output of
the spawned task. For example:
use tokio::task;
# #[tokio::main(flavor = "current_thread")]
# async fn main() -> Result<(), Box<dyn std::error::Error>> {
let join = task::spawn(async {
// ...
"hello world!"
});
// ...
// Await the result of the spawned task.
let result = join.await?;
assert_eq!(result, "hello world!");
# Ok(())
# }
Again, like std::thread's JoinHandle type, if the spawned
task panics, awaiting its JoinHandle will return a JoinError. For
example:
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::task;
# #[tokio::main] async fn main() {
let join = task::spawn(async {
panic!("something bad happened!")
});
// The returned result indicates that the task failed.
assert!(join.await.is_err());
# }
# }
spawn, JoinHandle, and JoinError are present when the "rt"
feature flag is enabled.
Cancellation
Spawned tasks may be cancelled using the JoinHandle::abort or
AbortHandle::abort methods. When one of these methods are called, the
task is signalled to shut down next time it yields at an .await point. If
the task is already idle, then it will be shut down as soon as possible
without running again before being shut down. Additionally, shutting down a
Tokio runtime (e.g. by returning from #[tokio::main]) immediately cancels
all tasks on it.
When tasks are shut down, it will stop running at whichever .await it has
yielded at. All local variables are destroyed by running their destructor.
Once shutdown has completed, awaiting the JoinHandle will fail with a
cancelled error.
Note that aborting a task does not guarantee that it fails with a cancelled
error, since it may complete normally first. For example, if the task does
not yield to the runtime at any point between the call to abort and the
end of the task, then the JoinHandle will instead report that the task
exited normally.
Be aware that tasks spawned using spawn_blocking cannot be aborted
because they are not async. If you call abort on a spawn_blocking
task, then this will not have any effect, and the task will continue
running normally. The exception is if the task has not started running
yet; in that case, calling abort may prevent the task from starting.
Be aware that calls to JoinHandle::abort just schedule the task for
cancellation, and will return before the cancellation has completed. To wait
for cancellation to complete, wait for the task to finish by awaiting the
JoinHandle. Similarly, the JoinHandle::is_finished method does not
return true until the cancellation has finished.
Calling JoinHandle::abort multiple times has the same effect as calling
it once.
Tokio also provides an AbortHandle, which is like the JoinHandle,
except that it does not provide a mechanism to wait for the task to finish.
Each task can only have one JoinHandle, but it can have more than one
AbortHandle.
Blocking and Yielding
As we discussed above, code running in asynchronous tasks should not perform operations that can block. A blocking operation performed in a task running on a thread that is also running other tasks would block the entire thread, preventing other tasks from running.
Instead, Tokio provides two APIs for running blocking operations in an
asynchronous context: task::spawn_blocking and task::block_in_place.
Be aware that if you call a non-async method from async code, that non-async method is still inside the asynchronous context, so you should also avoid blocking operations there. This includes destructors of objects destroyed in async code.
spawn_blocking
The task::spawn_blocking function is similar to the task::spawn function
discussed in the previous section, but rather than spawning an
non-blocking future on the Tokio runtime, it instead spawns a
blocking function on a dedicated thread pool for blocking tasks. For
example:
use tokio::task;
# async fn docs() {
task::spawn_blocking(|| {
// do some compute-heavy work or call synchronous code
});
# }
Just like task::spawn, task::spawn_blocking returns a JoinHandle
which we can use to await the result of the blocking operation:
# use tokio::task;
# async fn docs() -> Result<(), Box<dyn std::error::Error>>{
let join = task::spawn_blocking(|| {
// do some compute-heavy work or call synchronous code
"blocking completed"
});
let result = join.await?;
assert_eq!(result, "blocking completed");
# Ok(())
# }
block_in_place
When using the multi-threaded runtime, the task::block_in_place
function is also available. Like task::spawn_blocking, this function
allows running a blocking operation from an asynchronous context. Unlike
spawn_blocking, however, block_in_place works by transitioning the
current worker thread to a blocking thread, moving other tasks running on
that thread to another worker thread. This can improve performance by avoiding
context switches.
For example:
# #[cfg(not(target_family = "wasm"))]
# {
use tokio::task;
# async fn docs() {
let result = task::block_in_place(|| {
// do some compute-heavy work or call synchronous code
"blocking completed"
});
assert_eq!(result, "blocking completed");
# }
# }
yield_now
In addition, this module provides a task::yield_now async function
that is analogous to the standard library's thread::yield_now. Calling
and awaiting this function will cause the current task to yield to the
Tokio runtime's scheduler, allowing other tasks to be
scheduled. Eventually, the yielding task will be polled again, allowing it
to execute. For example:
use tokio::task;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
async {
task::spawn(async {
// ...
println!("spawned task done!")
});
// Yield, allowing the newly-spawned task to execute first.
task::yield_now().await;
println!("main task done!");
}
# .await;
# }
pub mod task { /* ... */ }
Modules
Module coop
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")Other("#[<cfg_attr>(not(feature = \"full\"), allow(dead_code))]")Other("#[<cfg_attr>(not(feature = \"rt\"), allow(unreachable_pub))]")
Utilities for improved cooperative scheduling.
Cooperative scheduling
A single call to poll on a top-level task may potentially do a lot of
work before it returns Poll::Pending. If a task runs for a long period of
time without yielding back to the executor, it can starve other tasks
waiting on that executor to execute them, or drive underlying resources.
Since Rust does not have a runtime, it is difficult to forcibly preempt a
long-running task. Instead, this module provides an opt-in mechanism for
futures to collaborate with the executor to avoid starvation.
Consider a future like this one:
# use tokio_stream::{Stream, StreamExt};
async fn drop_all<I: Stream + Unpin>(mut input: I) {
while let Some(_) = input.next().await {}
}
It may look harmless, but consider what happens under heavy load if the
input stream is always ready. If we spawn drop_all, the task will never
yield, and will starve other tasks and resources on the same executor.
To account for this, Tokio has explicit yield points in a number of library functions, which force tasks to return to the executor periodically.
unconstrained
If necessary, task::unconstrained lets you opt a future out of Tokio's cooperative
scheduling. When a future is wrapped with unconstrained, it will never be forced to yield to
Tokio. For example:
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
use tokio::{task, sync::mpsc};
let fut = async {
let (tx, mut rx) = mpsc::unbounded_channel();
for i in 0..1000 {
let _ = tx.send(());
// This will always be ready. If coop was in effect, this code would be forced to yield
// periodically. However, if left unconstrained, then this code will never yield.
rx.recv().await;
}
};
task::coop::unconstrained(fut).await;
# }
pub mod coop { /* ... */ }
Types
Struct RestoreOnPending
Attributes:
Other("#[<cfg>(any(feature = \"fs\", feature = \"io-std\", feature = \"net\", feature =\n\"process\", feature = \"rt\", feature = \"signal\", feature = \"sync\", feature =\n\"time\",))]")MustUse { reason: None }
Value returned by the [poll_proceed] method.
pub struct RestoreOnPending(/* private field */, /* private field */);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | private |
Private field |
| 1 | private |
Private field |
Implementations
Methods
-
Signals that the task that obtained this
pub fn made_progress(self: &Self) { /* ... */ }RestoreOnPendingwas able to make
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Coop
Attributes:
MustUse { reason: Some("futures do nothing unless polled") }
Future wrapper to ensure cooperative scheduling created by [cooperative].
pub struct Coop<F: Future> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Future
-
fn poll(self: Pin<&mut Self>, cx: &mut Context<''_>) -> Poll<<Self as >::Output> { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
IntoFuture
-
fn into_future(self: Self) -> <F as IntoFuture>::IntoFuture { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Functions
Function has_budget_remaining
Attributes:
Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")Other("#[attr = Inline(Always)]")
Returns true if there is still budget left on the task.
Examples
This example defines a Timeout future that requires a given future to complete before the
specified duration elapses. If it does, its result is returned; otherwise, an error is returned
and the future is canceled.
Note that the future could exhaust the budget before we evaluate the timeout. Using has_budget_remaining,
we can detect this scenario and ensure the timeout is always checked.
# use std::future::Future;
# use std::pin::{pin, Pin};
# use std::task::{ready, Context, Poll};
# use tokio::task::coop;
# use tokio::time::Sleep;
pub struct Timeout<T> {
future: T,
delay: Pin<Box<Sleep>>,
}
impl<T> Future for Timeout<T>
where
T: Future + Unpin,
{
type Output = Result<T::Output, ()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = Pin::into_inner(self);
let future = Pin::new(&mut this.future);
let delay = Pin::new(&mut this.delay);
// check if the future is ready
let had_budget_before = coop::has_budget_remaining();
if let Poll::Ready(v) = future.poll(cx) {
return Poll::Ready(Ok(v));
}
let has_budget_now = coop::has_budget_remaining();
// evaluate the timeout
if let (true, false) = (had_budget_before, has_budget_now) {
// it is the underlying future that exhausted the budget
ready!(pin!(coop::unconstrained(delay)).poll(cx));
} else {
ready!(delay.poll(cx));
}
return Poll::Ready(Err(()));
}
}
pub fn has_budget_remaining() -> bool { /* ... */ }
Function poll_proceed
Attributes:
Other("#[<cfg>(any(feature = \"fs\", feature = \"io-std\", feature = \"net\", feature =\n\"process\", feature = \"rt\", feature = \"signal\", feature = \"sync\", feature =\n\"time\",))]")Other("#[attr = Inline(Hint)]")
Decrements the task budget and returns [Poll::Pending] if the budget is depleted.
This indicates that the task should yield to the scheduler. Otherwise, returns
[RestoreOnPending] which can be used to commit the budget consumption.
The returned [RestoreOnPending] will revert the budget to its former
value when dropped unless [RestoreOnPending::made_progress]
is called. It is the caller's responsibility to do so when it was able to
make progress after the call to [poll_proceed].
Restoring the budget automatically ensures the task can try to make progress in some other
way.
Note that [RestoreOnPending] restores the budget as it was before [poll_proceed].
Therefore, if the budget is further adjusted between when [poll_proceed] returns and
[RestoreOnPending] is dropped, those adjustments are erased unless the caller indicates
that progress was made.
Examples
This example wraps the futures::channel::mpsc::UnboundedReceiver to
cooperate with the Tokio scheduler. Each time a value is received, task budget
is consumed. If no budget is available, the task yields to the scheduler.
use std::pin::Pin;
use std::task::{ready, Context, Poll};
use tokio::task::coop;
use futures::stream::{Stream, StreamExt};
use futures::channel::mpsc::UnboundedReceiver;
struct CoopUnboundedReceiver<T> {
receiver: UnboundedReceiver<T>,
}
impl<T> Stream for CoopUnboundedReceiver<T> {
type Item = T;
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<Option<T>> {
let coop = ready!(coop::poll_proceed(cx));
match self.receiver.poll_next_unpin(cx) {
Poll::Ready(v) => {
// We received a value, so consume budget.
coop.made_progress();
Poll::Ready(v)
}
Poll::Pending => Poll::Pending,
}
}
}
pub fn poll_proceed(cx: &mut std::task::Context<''_>) -> std::task::Poll<RestoreOnPending> { /* ... */ }
Function cooperative
Attributes:
Other("#[<cfg>(any(feature = \"fs\", feature = \"io-std\", feature = \"net\", feature =\n\"process\", feature = \"rt\", feature = \"signal\", feature = \"sync\", feature =\n\"time\",))]")Other("#[attr = Inline(Hint)]")
Creates a wrapper future that makes the inner future cooperate with the Tokio scheduler.
When polled, the wrapper will first call [poll_proceed] to consume task budget, and
immediately yield if the budget has been depleted. If budget was available, the inner future
is polled. The budget consumption will be made final using [RestoreOnPending::made_progress]
if the inner future resolves to its final value.
Examples
When you call recv on the Receiver of a tokio::sync::mpsc
channel, task budget will automatically be consumed when the next value is returned.
This makes tasks that use Tokio mpsc channels automatically cooperative.
If you're using futures::channel::mpsc
instead, automatic task budget consumption will not happen. This example shows how can use
cooperative to make futures::channel::mpsc channels cooperate with the scheduler in the
same way Tokio channels do.
use tokio::task::coop::cooperative;
use futures::channel::mpsc::Receiver;
use futures::stream::StreamExt;
async fn receive_next<T>(receiver: &mut Receiver<T>) -> Option<T> {
// Use `StreamExt::next` to obtain a `Future` that resolves to the next value
let recv_future = receiver.next();
// Wrap it a cooperative wrapper
let coop_future = cooperative(recv_future);
// And await
coop_future.await
}
```rust
pub fn cooperative<F: Future>(fut: F) -> Coop<F> { /* ... */ }
Re-exports
Re-export consume_budget
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use consume_budget::consume_budget;
Re-export unconstrained
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use unconstrained::unconstrained;
Re-export Unconstrained
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use unconstrained::Unconstrained;
Module join_set
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")Other("#[<cfg>(tokio_unstable)]")
A collection of tasks spawned on a Tokio runtime.
This module provides the [JoinSet] type, a collection which stores a set
of spawned tasks and allows asynchronously awaiting the output of those
tasks as they complete. See the documentation for the [JoinSet] type for
details.
pub mod join_set { /* ... */ }
Types
Struct JoinSet
Attributes:
Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
A collection of tasks spawned on a Tokio runtime.
A JoinSet can be used to await the completion of some or all of the tasks
in the set. The set is not ordered, and the tasks will be returned in the
order they complete.
All of the tasks must have the same return type T.
When the JoinSet is dropped, all tasks in the JoinSet are immediately aborted.
Examples
Spawn multiple tasks and wait for them.
use tokio::task::JoinSet;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut set = JoinSet::new();
for i in 0..10 {
set.spawn(async move { i });
}
let mut seen = [false; 10];
while let Some(res) = set.join_next().await {
let idx = res.unwrap();
seen[idx] = true;
}
for i in 0..10 {
assert!(seen[i]);
}
# }
Task ID guarantees
While a task is tracked in a JoinSet, that task's ID is unique relative
to all other running tasks in Tokio. For this purpose, tracking a task in a
JoinSet is equivalent to holding a JoinHandle to it. See the task ID
documentation for more info.
pub struct JoinSet<T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn new() -> Self { /* ... */ }Create a new
JoinSet. -
pub fn len(self: &Self) -> usize { /* ... */ }Returns the number of tasks currently in the
JoinSet. -
pub fn is_empty(self: &Self) -> bool { /* ... */ }Returns whether the
JoinSetis empty. -
pub fn build_task(self: &mut Self) -> Builder<''_, T> { /* ... */ }Returns a
Builderthat can be used to configure a task prior to -
pub fn spawn<F>(self: &mut Self, task: F) -> AbortHandle
where F: Future<Output = T> + Send + ''static, T: Send { /* ... */ }
Spawn the provided task on the `JoinSet`, returning an [`AbortHandle`]
- ```rust
pub fn spawn_on<F>(self: &mut Self, task: F, handle: &Handle) -> AbortHandle
where
F: Future<Output = T> + Send + ''static,
T: Send { /* ... */ }
Spawn the provided task on the provided runtime and store it in this
-
pub fn spawn_local<F>(self: &mut Self, task: F) -> AbortHandle
where F: Future<Output = T> + ''static { /* ... */ }
Spawn the provided task on the current [`LocalSet`] or [`LocalRuntime`]
- ```rust
pub fn spawn_local_on<F>(self: &mut Self, task: F, local_set: &LocalSet) -> AbortHandle
where
F: Future<Output = T> + ''static { /* ... */ }
Spawn the provided task on the provided [LocalSet] and store it in
-
pub fn spawn_blocking<F>(self: &mut Self, f: F) -> AbortHandle
where F: FnOnce() -> T + Send + ''static, T: Send { /* ... */ }
Spawn the blocking code on the blocking threadpool and store
- ```rust
pub fn spawn_blocking_on<F>(self: &mut Self, f: F, handle: &Handle) -> AbortHandle
where
F: FnOnce() -> T + Send + ''static,
T: Send { /* ... */ }
Spawn the blocking code on the blocking threadpool of the
-
pub async fn join_next(self: &mut Self) -> Option<Result<T, JoinError>> { /* ... */ }Waits until one of the tasks in the set completes and returns its output.
-
pub async fn join_next_with_id(self: &mut Self) -> Option<Result<(Id, T), JoinError>> { /* ... */ }Waits until one of the tasks in the set completes and returns its
-
pub fn try_join_next(self: &mut Self) -> Option<Result<T, JoinError>> { /* ... */ }Tries to join one of the tasks in the set that has completed and return its output.
-
pub fn try_join_next_with_id(self: &mut Self) -> Option<Result<(Id, T), JoinError>> { /* ... */ }Tries to join one of the tasks in the set that has completed and return its output,
-
pub async fn shutdown(self: &mut Self) { /* ... */ }Aborts all tasks and waits for them to finish shutting down.
-
pub async fn join_all(self: Self) -> Vec<T> { /* ... */ }Awaits the completion of all tasks in this
JoinSet, returning a vector of their results. -
pub fn abort_all(self: &mut Self) { /* ... */ }Aborts all tasks on this
JoinSet. -
pub fn detach_all(self: &mut Self) { /* ... */ }Removes all tasks from this
JoinSetwithout aborting them. -
pub fn poll_join_next(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<Result<T, JoinError>>> { /* ... */ }Polls for one of the tasks in the set to complete.
-
pub fn poll_join_next_with_id(self: &mut Self, cx: &mut Context<''_>) -> Poll<Option<Result<(Id, T), JoinError>>> { /* ... */ }Polls for one of the tasks in the set to complete.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Default
-
fn default() -> Self { /* ... */ }
-
-
Drop
-
fn drop(self: &mut Self) { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
FromIterator
-
fn from_iter<I: IntoIterator<Item = F>>(iter: I) -> Self { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Builder
Attributes:
Other("#[<cfg>(all(tokio_unstable, feature = \"tracing\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(tokio_unstable, feature = \"tracing\"))))]")Other("#[doc(cfg(all(tokio_unstable, feature = \"tracing\")))]")MustUse { reason: Some("builders do nothing unless used to spawn a task") }
A variant of task::Builder that spawns tasks on a [JoinSet] rather
than on the current default runtime.
pub struct Builder<''a, T> {
// Some fields omitted
}
Fields
| Name | Type | Documentation |
|---|---|---|
| private fields | ... | Some fields have been omitted |
Implementations
Methods
-
pub fn name(self: Self, name: &''a str) -> Self { /* ... */ }Assigns a name to the task which will be spawned.
-
pub fn spawn<F>(self: Self, future: F) -> std::io::Result<AbortHandle>
where F: Future<Output = T> + Send + ''static, T: Send { /* ... */ }
Spawn the provided task with this builder's settings and store it in the
- ```rust
pub fn spawn_on<F>(self: Self, future: F, handle: &Handle) -> std::io::Result<AbortHandle>
where
F: Future<Output = T> + Send + ''static,
T: Send { /* ... */ }
Spawn the provided task on the provided [runtime handle] with this
-
pub fn spawn_blocking<F>(self: Self, f: F) -> std::io::Result<AbortHandle>
where F: FnOnce() -> T + Send + ''static, T: Send { /* ... */ }
Spawn the blocking code on the blocking threadpool with this builder's
- ```rust
pub fn spawn_blocking_on<F>(self: Self, f: F, handle: &Handle) -> std::io::Result<AbortHandle>
where
F: FnOnce() -> T + Send + ''static,
T: Send { /* ... */ }
Spawn the blocking code on the blocking threadpool of the provided
-
pub fn spawn_local<F>(self: Self, future: F) -> std::io::Result<AbortHandle>
where F: Future<Output = T> + ''static { /* ... */ }
Spawn the provided task on the current [`LocalSet`] with this builder's
- ```rust
pub fn spawn_local_on<F>(self: Self, future: F, local_set: &LocalSet) -> std::io::Result<AbortHandle>
where
F: Future<Output = T> + ''static { /* ... */ }
Spawn the provided task on the provided [LocalSet] with this builder's
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Module futures
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
Task-related futures.
pub mod futures { /* ... */ }
Re-exports
Re-export TaskLocalFuture
pub use super::task_local::TaskLocalFuture;
Re-exports
Re-export JoinError
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use crate::runtime::task::JoinError;
Re-export JoinHandle
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use crate::runtime::task::JoinHandle;
Re-export spawn_blocking
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use blocking::spawn_blocking;
Re-export spawn
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use spawn::spawn;
Re-export block_in_place
Attributes:
Other("#[<cfg>(feature = \"rt-multi-thread\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt-multi-thread\")))]")Other("#[doc(cfg(feature = \"rt-multi-thread\"))]")
pub use blocking::block_in_place;
Re-export yield_now
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use yield_now::yield_now;
Re-export spawn_local
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use local::spawn_local;
Re-export LocalSet
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use local::LocalSet;
Re-export LocalEnterGuard
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use local::LocalEnterGuard;
Re-export LocalKey
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use task_local::LocalKey;
Re-export JoinSet
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")Other("#[doc(inline)]")
pub use join_set::JoinSet;
Re-export AbortHandle
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use crate::runtime::task::AbortHandle;
Re-export Id
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use crate::runtime::task::Id;
Re-export id
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use crate::runtime::task::id;
Re-export try_id
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use crate::runtime::task::try_id;
Re-export Builder
Attributes:
Other("#[<cfg>(all(tokio_unstable, feature = \"tracing\"))]")Other("#[<cfg_attr>(docsrs, doc(cfg(all(tokio_unstable, feature = \"tracing\"))))]")Other("#[doc(cfg(all(tokio_unstable, feature = \"tracing\")))]")
pub use builder::Builder;
Module time
Attributes:
Other("#[<cfg>(feature = \"time\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"time\")))]")Other("#[doc(cfg(feature = \"time\"))]")
Utilities for tracking time.
This module provides a number of types for executing code after a set period of time.
-
Sleepis a future that does no work and completes at a specific [Instant] in time. -
Intervalis a stream yielding a value at a fixed period. It is initialized with a [Duration] and repeatedly yields each time the duration elapses. -
[
Timeout]: Wraps a future or stream, setting an upper bound to the amount of time it is allowed to execute. If the future or stream does not complete in time, then it is canceled and an error is returned.
These types are sufficient for handling a large number of scenarios involving time.
These types must be used from within the context of the Runtime.
Examples
Wait 100ms and print "100 ms have elapsed"
use std::time::Duration;
use tokio::time::sleep;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
sleep(Duration::from_millis(100)).await;
println!("100 ms have elapsed");
# }
Require that an operation takes no more than 1s.
use tokio::time::{timeout, Duration};
async fn long_future() {
// do work here
}
# async fn dox() {
let res = timeout(Duration::from_secs(1), long_future()).await;
if res.is_err() {
println!("operation timed out");
}
# }
A simple example using interval to execute a task every two seconds.
The difference between interval and sleep is that an interval
measures the time since the last tick, which means that .tick().await may
wait for a shorter time than the duration specified for the interval
if some time has passed between calls to .tick().await.
If the tick in the example below was replaced with sleep, the task
would only be executed once every three seconds, and not every two
seconds.
use tokio::time;
async fn task_that_takes_a_second() {
println!("hello");
time::sleep(time::Duration::from_secs(1)).await
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut interval = time::interval(time::Duration::from_secs(2));
for _i in 0..5 {
interval.tick().await;
task_that_takes_a_second().await;
}
# }
pub mod time { /* ... */ }
Modules
Module error
Time error types.
pub mod error { /* ... */ }
Types
Struct Error
Errors encountered by the timer implementation.
Currently, there are two different errors that can occur:
-
shutdownoccurs when a timer operation is attempted, but the timer instance has been dropped. In this case, the operation will never be able to complete and theshutdownerror is returned. This is a permanent error, i.e., once this error is observed, timer operations will never succeed in the future. -
at_capacityoccurs when a timer operation is attempted, but the timer instance is currently handling its maximum number of outstanding sleep instances. In this case, the operation is not able to be performed at the current moment, andat_capacityis returned. This is a transient error, i.e., at some point in the future, if the operation is attempted again, it might succeed. Callers that observe this error should attempt to shed load. One way to do this would be dropping the future that issued the timer operation.
pub struct Error(/* private field */);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | private |
Private field |
Implementations
Methods
-
pub fn shutdown() -> Error { /* ... */ }Creates an error representing a shutdown timer.
-
pub fn is_shutdown(self: &Self) -> bool { /* ... */ }Returns
trueif the error was caused by the timer being shutdown. -
pub fn at_capacity() -> Error { /* ... */ }Creates an error representing a timer at capacity.
-
pub fn is_at_capacity(self: &Self) -> bool { /* ... */ }Returns
trueif the error was caused by the timer being at capacity. -
pub fn invalid() -> Error { /* ... */ }Creates an error representing a misconfigured timer.
-
pub fn is_invalid(self: &Self) -> bool { /* ... */ }Returns
trueif the error was caused by the timer being misconfigured.
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Clone
-
fn clone(self: &Self) -> Error { /* ... */ }
-
-
CloneToUninit
-
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8) { /* ... */ }
-
-
Copy
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Error
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Sync
-
ToOwned
-
fn to_owned(self: &Self) -> T { /* ... */ } -
fn clone_into(self: &Self, target: &mut T) { /* ... */ }
-
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Struct Elapsed
Errors returned by Timeout.
This error is returned when a timeout expires before the function was able to finish.
pub struct Elapsed(/* private field */);
Fields
| Index | Type | Documentation |
|---|---|---|
| 0 | private |
Private field |
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Display
-
fn fmt(self: &Self, fmt: &mut fmt::Formatter<''_>) -> fmt::Result { /* ... */ }
-
-
Eq
-
Error
-
Freeze
-
From
-
fn from(t: T) -> T { /* ... */ }Returns the argument unchanged.
-
fn from(_err: Elapsed) -> std::io::Error { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
PartialEq
-
fn eq(self: &Self, other: &Elapsed) -> bool { /* ... */ }
-
-
RefUnwindSafe
-
Send
-
StructuralPartialEq
-
Sync
-
ToString
-
fn to_string(self: &Self) -> String { /* ... */ }
-
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Re-exports
Re-export advance
Attributes:
Other("#[<cfg>(feature = \"test-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"test-util\")))]")Other("#[doc(cfg(feature = \"test-util\"))]")
pub use clock::advance;
Re-export pause
Attributes:
Other("#[<cfg>(feature = \"test-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"test-util\")))]")Other("#[doc(cfg(feature = \"test-util\"))]")
pub use clock::pause;
Re-export resume
Attributes:
Other("#[<cfg>(feature = \"test-util\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"test-util\")))]")Other("#[doc(cfg(feature = \"test-util\"))]")
pub use clock::resume;
Re-export Instant
pub use self::instant::Instant;
Re-export interval
pub use interval::interval;
Re-export interval_at
pub use interval::interval_at;
Re-export Interval
pub use interval::Interval;
Re-export MissedTickBehavior
pub use interval::MissedTickBehavior;
Re-export sleep
pub use sleep::sleep;
Re-export sleep_until
pub use sleep::sleep_until;
Re-export Sleep
pub use sleep::Sleep;
Re-export timeout
Attributes:
Other("#[doc(inline)]")
pub use timeout::timeout;
Re-export timeout_at
Attributes:
Other("#[doc(inline)]")
pub use timeout::timeout_at;
Re-export Timeout
Attributes:
Other("#[doc(inline)]")
pub use timeout::Timeout;
Re-export Duration
Attributes:
Other("#[doc(no_inline)]")
pub use std::time::Duration;
Module stream
Due to the Stream trait's inclusion in std landing later than Tokio's 1.0
release, most of the Tokio stream utilities have been moved into the tokio-stream
crate.
Why was Stream not included in Tokio 1.0?
Originally, we had planned to ship Tokio 1.0 with a stable Stream type
but unfortunately the RFC had not been merged in time for Stream to
reach std on a stable compiler in time for the 1.0 release of Tokio. For
this reason, the team has decided to move all Stream based utilities to
the tokio-stream crate. While this is not ideal, once Stream has made
it into the standard library and the MSRV period has passed, we will implement
stream for our different types.
While this may seem unfortunate, not all is lost as you can get much of the
Stream support with async/await and while let loops. It is also possible
to create a impl Stream from async fn using the async-stream crate.
Example
Convert a [sync::mpsc::Receiver] to an impl Stream.
use tokio::sync::mpsc;
let (tx, mut rx) = mpsc::channel::<usize>(16);
let stream = async_stream::stream! {
while let Some(item) = rx.recv().await {
yield item;
}
};
pub mod stream { /* ... */ }
Module doc
Attributes:
Other("#[<cfg>(all(docsrs, unix))]")
Types which are documented locally in the Tokio crate, but does not actually live here.
Note this module is only visible on docs.rs, you cannot use it directly in your own code.
pub mod doc { /* ... */ }
Modules
Module os
Attributes:
Other("#[<cfg>(any(feature = \"net\", feature = \"fs\"))]")
See std::os.
pub mod os { /* ... */ }
Modules
Module windows
Platform-specific extensions to std for Windows.
See std::os::windows.
pub mod windows { /* ... */ }
Modules
Module io
Windows-specific extensions to general I/O primitives.
See std::os::windows::io.
pub mod io { /* ... */ }
Types
Type Alias RawHandle
See std::os::windows::io::RawHandle
pub type RawHandle = crate::doc::NotDefinedHere;
Type Alias OwnedHandle
See std::os::windows::io::OwnedHandle
pub type OwnedHandle = crate::doc::NotDefinedHere;
Type Alias RawSocket
See std::os::windows::io::RawSocket
pub type RawSocket = crate::doc::NotDefinedHere;
Type Alias BorrowedHandle
See std::os::windows::io::BorrowedHandle
pub type BorrowedHandle<''handle> = crate::doc::NotDefinedHere;
Type Alias BorrowedSocket
See std::os::windows::io::BorrowedSocket
pub type BorrowedSocket<''socket> = crate::doc::NotDefinedHere;
Traits
Trait AsRawHandle
See std::os::windows::io::AsRawHandle
pub trait AsRawHandle {
/* Associated items */
}
Required Items
Required Methods
as_raw_handle: Seestd::os::windows::io::AsRawHandle::as_raw_handle
Implementations
This trait is implemented for the following types:
FileStderrStdinStdoutNamedPipeServerNamedPipeClientChildStdinChildStdoutChildStderr
Trait FromRawHandle
See std::os::windows::io::FromRawHandle
pub trait FromRawHandle {
/* Associated items */
}
This trait is not object-safe and cannot be used in dynamic trait objects.
Required Items
Required Methods
from_raw_handle: Seestd::os::windows::io::FromRawHandle::from_raw_handle
Implementations
This trait is implemented for the following types:
File
Trait AsRawSocket
See std::os::windows::io::AsRawSocket
pub trait AsRawSocket {
/* Associated items */
}
Required Items
Required Methods
as_raw_socket: Seestd::os::windows::io::AsRawSocket::as_raw_socket
Implementations
This trait is implemented for the following types:
TcpListenerTcpSocketTcpStreamUdpSocket
Trait FromRawSocket
See std::os::windows::io::FromRawSocket
pub trait FromRawSocket {
/* Associated items */
}
This trait is not object-safe and cannot be used in dynamic trait objects.
Required Items
Required Methods
from_raw_socket: Seestd::os::windows::io::FromRawSocket::from_raw_socket
Implementations
This trait is implemented for the following types:
TcpSocket
Trait IntoRawSocket
See std::os::windows::io::IntoRawSocket
pub trait IntoRawSocket {
/* Associated items */
}
Required Items
Required Methods
into_raw_socket: Seestd::os::windows::io::IntoRawSocket::into_raw_socket
Implementations
This trait is implemented for the following types:
TcpSocket
Trait AsHandle
See std::os::windows::io::AsHandle
pub trait AsHandle {
/* Associated items */
}
Required Items
Required Methods
as_handle: Seestd::os::windows::io::AsHandle::as_handle
Implementations
This trait is implemented for the following types:
FileStderrStdinStdoutNamedPipeServerNamedPipeClientChildStdinChildStdoutChildStderr
Trait AsSocket
See std::os::windows::io::AsSocket
pub trait AsSocket {
/* Associated items */
}
Required Items
Required Methods
as_socket: Seestd::os::windows::io::AsSocket::as_socket
Implementations
This trait is implemented for the following types:
TcpListenerTcpSocketTcpStreamUdpSocket
Types
Enum NotDefinedHere
The name of a type which is not defined here.
This is typically used as an alias for another type, like so:
/// See [some::other::location](https://example.com).
type DEFINED_ELSEWHERE = crate::doc::NotDefinedHere;
This type is uninhabitable like the never type to ensure that no one
will ever accidentally use it.
pub enum NotDefinedHere {
}
Variants
Implementations
Trait Implementations
-
Any
-
fn type_id(self: &Self) -> TypeId { /* ... */ }
-
-
Borrow
-
fn borrow(self: &Self) -> &T { /* ... */ }
-
-
BorrowMut
-
fn borrow_mut(self: &mut Self) -> &mut T { /* ... */ }
-
-
Debug
-
fn fmt(self: &Self, f: &mut $crate::fmt::Formatter<''_>) -> $crate::fmt::Result { /* ... */ }
-
-
Freeze
-
From
-
Returns the argument unchanged.
fn from(t: T) -> T { /* ... */ }
-
-
Instrument
-
Into
-
Calls
fn into(self: Self) -> U { /* ... */ }U::from(self).
-
-
RefUnwindSafe
-
Send
-
Source
-
fn register(self: &mut Self, _registry: &mio::Registry, _token: mio::Token, _interests: mio::Interest) -> std::io::Result<()> { /* ... */ } -
fn reregister(self: &mut Self, _registry: &mio::Registry, _token: mio::Token, _interests: mio::Interest) -> std::io::Result<()> { /* ... */ } -
fn deregister(self: &mut Self, _registry: &mio::Registry) -> std::io::Result<()> { /* ... */ }
-
-
Sync
-
TryFrom
-
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error> { /* ... */ }
-
-
TryInto
-
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error> { /* ... */ }
-
-
Unpin
-
UnwindSafe
-
WithSubscriber
Macros
Macro pin
Attributes:
MacroExport
Pins a value on the stack.
Calls to async fn return anonymous Future values that are !Unpin.
These values must be pinned before they can be polled. Calling .await will
handle this, but consumes the future. If it is required to call .await on
a &mut _ reference, the caller is responsible for pinning the future.
Pinning may be done by allocating with Box::pin or by using the stack
with the pin! macro.
The following will fail to compile:
async fn my_async_fn() {
// async logic here
}
#[tokio::main]
async fn main() {
let mut future = my_async_fn();
(&mut future).await;
}
To make this work requires pinning:
use tokio::pin;
async fn my_async_fn() {
// async logic here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let future = my_async_fn();
pin!(future);
(&mut future).await;
# }
Pinning is useful when using select! and stream operators that require T: Stream + Unpin.
Usage
The pin! macro takes identifiers as arguments. It does not work
with expressions.
The following does not compile as an expression is passed to pin!.
async fn my_async_fn() {
// async logic here
}
#[tokio::main]
async fn main() {
let mut future = pin!(my_async_fn());
(&mut future).await;
}
Examples
Using with select:
use tokio::{pin, select};
use tokio_stream::{self as stream, StreamExt};
async fn my_async_fn() {
// async logic here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut stream = stream::iter(vec![1, 2, 3, 4]);
let future = my_async_fn();
pin!(future);
loop {
select! {
_ = &mut future => {
// Stop looping `future` will be polled after completion
break;
}
Some(val) = stream.next() => {
println!("got value = {}", val);
}
}
}
# }
Because assigning to a variable followed by pinning is common, there is also a variant of the macro that supports doing both in one go.
use tokio::{pin, select};
async fn my_async_fn() {
// async logic here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
pin! {
let future1 = my_async_fn();
let future2 = my_async_fn();
}
select! {
_ = &mut future1 => {}
_ = &mut future2 => {}
}
# }
pub macro_rules! pin {
/* macro_rules! pin {
($($x:ident),*) => { ... };
($(
let $x:ident = $init:expr;
)*) => { ... };
} */
}
Macro select
Attributes:
Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")Other("#[doc(cfg(feature = \"macros\"))]")MacroExport
Waits on multiple concurrent branches, returning when the first branch completes, cancelling the remaining branches.
The select! macro must be used inside of async functions, closures, and
blocks.
The select! macro accepts one or more branches with the following pattern:
<pattern> = <async expression> (, if <precondition>)? => <handler>,
Additionally, the select! macro may include a single, optional else
branch, which evaluates if none of the other branches match their patterns:
else => <expression>
The macro aggregates all <async expression> expressions and runs them
concurrently on the current task. Once the first expression
completes with a value that matches its <pattern>, the select! macro
returns the result of evaluating the completed branch's <handler>
expression.
Additionally, each branch may include an optional if precondition. If the
precondition returns false, then the branch is disabled. The provided
<async expression> is still evaluated but the resulting future is never
polled. This capability is useful when using select! within a loop.
The complete lifecycle of a select! expression is as follows:
- Evaluate all provided
<precondition>expressions. If the precondition returnsfalse, disable the branch for the remainder of the current call toselect!. Re-enteringselect!due to a loop clears the "disabled" state. - Aggregate the
<async expression>s from each branch, including the disabled ones. If the branch is disabled,<async expression>is still evaluated, but the resulting future is not polled. - If all branches are disabled: go to step 6.
- Concurrently await on the results for all remaining
<async expression>s. - Once an
<async expression>returns a value, attempt to apply the value to the provided<pattern>. If the pattern matches, evaluate the<handler>and return. If the pattern does not match, disable the current branch for the remainder of the current call toselect!. Continue from step 3. - Evaluate the
elseexpression. If no else expression is provided, panic.
Runtime characteristics
By running all async expressions on the current task, the expressions are
able to run concurrently but not in parallel. This means all
expressions are run on the same thread and if one branch blocks the thread,
all other expressions will be unable to continue. If parallelism is
required, spawn each async expression using tokio::spawn and pass the
join handle to select!.
Fairness
By default, select! randomly picks a branch to check first. This provides
some level of fairness when calling select! in a loop with branches that
are always ready.
This behavior can be overridden by adding biased; to the beginning of the
macro usage. See the examples for details. This will cause select to poll
the futures in the order they appear from top to bottom. There are a few
reasons you may want this:
- The random number generation of
tokio::select!has a non-zero CPU cost - Your futures may interact in a way where known polling order is significant
But there is an important caveat to this mode. It becomes your responsibility
to ensure that the polling order of your futures is fair. If for example you
are selecting between a stream and a shutdown future, and the stream has a
huge volume of messages and zero or nearly zero time between them, you should
place the shutdown future earlier in the select! list to ensure that it is
always polled, and will not be ignored due to the stream being constantly
ready.
Panics
The select! macro panics if all branches are disabled and there is no
provided else branch. A branch is disabled when the provided if
precondition returns false or when the pattern does not match the
result of <async expression>.
Cancellation safety
When using select! in a loop to receive messages from multiple sources,
you should make sure that the receive call is cancellation safe to avoid
losing messages. This section goes through various common methods and
describes whether they are cancel safe. The lists in this section are not
exhaustive.
The following methods are cancellation safe:
tokio::sync::mpsc::Receiver::recvtokio::sync::mpsc::UnboundedReceiver::recvtokio::sync::broadcast::Receiver::recvtokio::sync::watch::Receiver::changedtokio::net::TcpListener::accepttokio::net::UnixListener::accepttokio::signal::unix::Signal::recvtokio::io::AsyncReadExt::readon anyAsyncReadtokio::io::AsyncReadExt::read_bufon anyAsyncReadtokio::io::AsyncWriteExt::writeon anyAsyncWritetokio::io::AsyncWriteExt::write_bufon anyAsyncWritetokio_stream::StreamExt::nexton anyStreamfutures::stream::StreamExt::nexton anyStream
The following methods are not cancellation safe and can lead to loss of data:
tokio::io::AsyncReadExt::read_exacttokio::io::AsyncReadExt::read_to_endtokio::io::AsyncReadExt::read_to_stringtokio::io::AsyncWriteExt::write_all
The following methods are not cancellation safe because they use a queue for fairness and cancellation makes you lose your place in the queue:
tokio::sync::Mutex::locktokio::sync::RwLock::readtokio::sync::RwLock::writetokio::sync::Semaphore::acquiretokio::sync::Notify::notified
To determine whether your own methods are cancellation safe, look for the
location of uses of .await. This is because when an asynchronous method is
cancelled, that always happens at an .await. If your function behaves
correctly even if it is restarted while waiting at an .await, then it is
cancellation safe.
Cancellation safety can be defined in the following way: If you have a
future that has not yet completed, then it must be a no-op to drop that
future and recreate it. This definition is motivated by the situation where
a select! is used in a loop. Without this guarantee, you would lose your
progress when another branch completes and you restart the select! by
going around the loop.
Be aware that cancelling something that is not cancellation safe is not necessarily wrong. For example, if you are cancelling a task because the application is shutting down, then you probably don't care that partially read data is lost.
Examples
Basic select with two branches.
async fn do_stuff_async() {
// async work
}
async fn more_async_work() {
// more here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
tokio::select! {
_ = do_stuff_async() => {
println!("do_stuff_async() completed first")
}
_ = more_async_work() => {
println!("more_async_work() completed first")
}
};
# }
Basic stream selecting.
use tokio_stream::{self as stream, StreamExt};
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut stream1 = stream::iter(vec![1, 2, 3]);
let mut stream2 = stream::iter(vec![4, 5, 6]);
let next = tokio::select! {
v = stream1.next() => v.unwrap(),
v = stream2.next() => v.unwrap(),
};
assert!(next == 1 || next == 4);
# }
Collect the contents of two streams. In this example, we rely on pattern
matching and the fact that stream::iter is "fused", i.e. once the stream
is complete, all calls to next() return None.
use tokio_stream::{self as stream, StreamExt};
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut stream1 = stream::iter(vec![1, 2, 3]);
let mut stream2 = stream::iter(vec![4, 5, 6]);
let mut values = vec![];
loop {
tokio::select! {
Some(v) = stream1.next() => values.push(v),
Some(v) = stream2.next() => values.push(v),
else => break,
}
}
values.sort();
assert_eq!(&[1, 2, 3, 4, 5, 6], &values[..]);
# }
Using the same future in multiple select! expressions can be done by passing
a reference to the future. Doing so requires the future to be Unpin. A
future can be made Unpin by either using Box::pin or stack pinning.
Here, a stream is consumed for at most 1 second.
use tokio_stream::{self as stream, StreamExt};
use tokio::time::{self, Duration};
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut stream = stream::iter(vec![1, 2, 3]);
let sleep = time::sleep(Duration::from_secs(1));
tokio::pin!(sleep);
loop {
tokio::select! {
maybe_v = stream.next() => {
if let Some(v) = maybe_v {
println!("got = {}", v);
} else {
break;
}
}
_ = &mut sleep => {
println!("timeout");
break;
}
}
}
# }
Joining two values using select!.
use tokio::sync::oneshot;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (tx1, mut rx1) = oneshot::channel();
let (tx2, mut rx2) = oneshot::channel();
tokio::spawn(async move {
tx1.send("first").unwrap();
});
tokio::spawn(async move {
tx2.send("second").unwrap();
});
let mut a = None;
let mut b = None;
while a.is_none() || b.is_none() {
tokio::select! {
v1 = (&mut rx1), if a.is_none() => a = Some(v1.unwrap()),
v2 = (&mut rx2), if b.is_none() => b = Some(v2.unwrap()),
}
}
let res = (a.unwrap(), b.unwrap());
assert_eq!(res.0, "first");
assert_eq!(res.1, "second");
# }
Using the biased; mode to control polling order.
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let mut count = 0u8;
loop {
tokio::select! {
// If you run this example without `biased;`, the polling order is
// pseudo-random, and the assertions on the value of count will
// (probably) fail.
biased;
_ = async {}, if count < 1 => {
count += 1;
assert_eq!(count, 1);
}
_ = async {}, if count < 2 => {
count += 1;
assert_eq!(count, 2);
}
_ = async {}, if count < 3 => {
count += 1;
assert_eq!(count, 3);
}
_ = async {}, if count < 4 => {
count += 1;
assert_eq!(count, 4);
}
else => {
break;
}
};
}
# }
Avoid racy if preconditions
Given that if preconditions are used to disable select! branches, some
caution must be used to avoid missing values.
For example, here is incorrect usage of sleep with if. The objective
is to repeatedly run an asynchronous task for up to 50 milliseconds.
However, there is a potential for the sleep completion to be missed.
use tokio::time::{self, Duration};
async fn some_async_work() {
// do work
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let sleep = time::sleep(Duration::from_millis(50));
tokio::pin!(sleep);
while !sleep.is_elapsed() {
tokio::select! {
_ = &mut sleep, if !sleep.is_elapsed() => {
println!("operation timed out");
}
_ = some_async_work() => {
println!("operation completed");
}
}
}
panic!("This example shows how not to do it!");
# }
In the above example, sleep.is_elapsed() may return true even if
sleep.poll() never returned Ready. This opens up a potential race
condition where sleep expires between the while !sleep.is_elapsed()
check and the call to select! resulting in the some_async_work() call to
run uninterrupted despite the sleep having elapsed.
One way to write the above example without the race would be:
use tokio::time::{self, Duration};
async fn some_async_work() {
# time::sleep(Duration::from_millis(10)).await;
// do work
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let sleep = time::sleep(Duration::from_millis(50));
tokio::pin!(sleep);
loop {
tokio::select! {
_ = &mut sleep => {
println!("operation timed out");
break;
}
_ = some_async_work() => {
println!("operation completed");
}
}
}
# }
Alternatives from the Ecosystem
The select! macro is a powerful tool for managing multiple asynchronous
branches, enabling tasks to run concurrently within the same thread. However,
its use can introduce challenges, particularly around cancellation safety, which
can lead to subtle and hard-to-debug errors. For many use cases, ecosystem
alternatives may be preferable as they mitigate these concerns by offering
clearer syntax, more predictable control flow, and reducing the need to manually
handle issues like fuse semantics or cancellation safety.
Merging Streams
For cases where loop { select! { ... } } is used to poll multiple tasks,
stream merging offers a concise alternative, inherently handle cancellation-safe
processing, removing the risk of data loss. Libraries such as tokio_stream,
futures::stream and futures_concurrency provide tools for merging
streams and handling their outputs sequentially.
Example with select!
struct File;
struct Channel;
struct Socket;
impl Socket {
async fn read_packet(&mut self) -> Vec<u8> {
vec![]
}
}
async fn read_send(_file: &mut File, _channel: &mut Channel) {
// do work that is not cancel safe
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
// open our IO types
let mut file = File;
let mut channel = Channel;
let mut socket = Socket;
loop {
tokio::select! {
_ = read_send(&mut file, &mut channel) => { /* ... */ },
_data = socket.read_packet() => { /* ... */ }
_ = futures::future::ready(()) => break
}
}
# }
Moving to merge
By using merge, you can unify multiple asynchronous tasks into a single stream, eliminating the need to manage tasks manually and reducing the risk of unintended behavior like data loss.
use std::pin::pin;
use futures::stream::unfold;
use tokio_stream::StreamExt;
struct File;
struct Channel;
struct Socket;
impl Socket {
async fn read_packet(&mut self) -> Vec<u8> {
vec![]
}
}
async fn read_send(_file: &mut File, _channel: &mut Channel) {
// do work that is not cancel safe
}
enum Message {
Stop,
Sent,
Data(Vec<u8>),
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
// open our IO types
let file = File;
let channel = Channel;
let socket = Socket;
let a = unfold((file, channel), |(mut file, mut channel)| async {
read_send(&mut file, &mut channel).await;
Some((Message::Sent, (file, channel)))
});
let b = unfold(socket, |mut socket| async {
let data = socket.read_packet().await;
Some((Message::Data(data), socket))
});
let c = tokio_stream::iter([Message::Stop]);
let mut s = pin!(a.merge(b).merge(c));
while let Some(msg) = s.next().await {
match msg {
Message::Data(_data) => { /* ... */ }
Message::Sent => continue,
Message::Stop => break,
}
}
# }
Racing Futures
If you need to wait for the first completion among several asynchronous tasks,
ecosystem utilities such as
futures,
futures-lite or
futures-concurrency
provide streamlined syntax for racing futures:
futures_concurrency::future::Racefutures::selectfutures::stream::select_all(for streams)futures_lite::future::orfutures_lite::future::race
use futures_concurrency::future::Race;
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let task_a = async { Ok("ok") };
let task_b = async { Err("error") };
let result = (task_a, task_b).race().await;
match result {
Ok(output) => println!("First task completed with: {output}"),
Err(err) => eprintln!("Error occurred: {err}"),
}
# }
pub macro_rules! select {
/* macro_rules! select {
{
$(
biased;
)?
$(
$bind:pat = $fut:expr $(, if $cond:expr)? => $handler:expr,
)*
$(
else => $els:expr $(,)?
)?
} => { ... };
} */
}
Macro join
Attributes:
Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")Other("#[doc(cfg(feature = \"macros\"))]")MacroExport
Waits on multiple concurrent branches, returning when all branches complete.
The join! macro must be used inside of async functions, closures, and
blocks.
The join! macro takes a list of async expressions and evaluates them
concurrently on the same task. Each async expression evaluates to a future
and the futures from each expression are multiplexed on the current task.
When working with async expressions returning Result, join! will wait
for all branches complete regardless if any complete with Err. Use
try_join! to return early when Err is encountered.
Notes
The supplied futures are stored inline and do not require allocating a
Vec.
Runtime characteristics
By running all async expressions on the current task, the expressions are
able to run concurrently but not in parallel. This means all
expressions are run on the same thread and if one branch blocks the thread,
all other expressions will be unable to continue. If parallelism is
required, spawn each async expression using tokio::spawn and pass the
join handle to join!.
Fairness
By default, join!'s generated future rotates which contained
future is polled first whenever it is woken.
This behavior can be overridden by adding biased; to the beginning of the
macro usage. See the examples for details. This will cause join to poll
the futures in the order they appear from top to bottom.
You may want this if your futures may interact in a way where known polling order is significant.
But there is an important caveat to this mode. It becomes your responsibility
to ensure that the polling order of your futures is fair. If for example you
are joining a stream and a shutdown future, and the stream has a
huge volume of messages that takes a long time to finish processing per poll, you should
place the shutdown future earlier in the join! list to ensure that it is
always polled, and will not be delayed due to the stream future taking a long time to return
Poll::Pending.
Examples
Basic join with two branches
async fn do_stuff_async() {
// async work
}
async fn more_async_work() {
// more here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (first, second) = tokio::join!(
do_stuff_async(),
more_async_work());
// do something with the values
# }
Using the biased; mode to control polling order.
# #[cfg(not(target_family = "wasm"))]
# {
async fn do_stuff_async() {
// async work
}
async fn more_async_work() {
// more here
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let (first, second) = tokio::join!(
biased;
do_stuff_async(),
more_async_work()
);
// do something with the values
# }
# }
pub macro_rules! join {
/* macro_rules! join {
($(biased;)? $($future:expr),*) => { ... };
} */
}
Macro try_join
Attributes:
Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")Other("#[doc(cfg(feature = \"macros\"))]")MacroExport
Waits on multiple concurrent branches, returning when all branches
complete with Ok(_) or on the first Err(_).
The try_join! macro must be used inside of async functions, closures, and
blocks.
Similar to join!, the try_join! macro takes a list of async
expressions and evaluates them concurrently on the same task. Each async
expression evaluates to a future and the futures from each expression are
multiplexed on the current task. The try_join! macro returns when all
branches return with Ok or when the first branch returns with Err.
Notes
The supplied futures are stored inline and do not require allocating a
Vec.
Runtime characteristics
By running all async expressions on the current task, the expressions are
able to run concurrently but not in parallel. This means all
expressions are run on the same thread and if one branch blocks the thread,
all other expressions will be unable to continue. If parallelism is
required, spawn each async expression using tokio::spawn and pass the
join handle to try_join!.
Fairness
By default, try_join!'s generated future rotates which
contained future is polled first whenever it is woken.
This behavior can be overridden by adding biased; to the beginning of the
macro usage. See the examples for details. This will cause try_join to poll
the futures in the order they appear from top to bottom.
You may want this if your futures may interact in a way where known polling order is significant.
But there is an important caveat to this mode. It becomes your responsibility
to ensure that the polling order of your futures is fair. If for example you
are joining a stream and a shutdown future, and the stream has a
huge volume of messages that takes a long time to finish processing per poll, you should
place the shutdown future earlier in the try_join! list to ensure that it is
always polled, and will not be delayed due to the stream future taking a long time to return
Poll::Pending.
Examples
Basic try_join with two branches.
async fn do_stuff_async() -> Result<(), &'static str> {
// async work
# Ok(())
}
async fn more_async_work() -> Result<(), &'static str> {
// more here
# Ok(())
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let res = tokio::try_join!(
do_stuff_async(),
more_async_work());
match res {
Ok((first, second)) => {
// do something with the values
}
Err(err) => {
println!("processing failed; error = {}", err);
}
}
# }
Using try_join! with spawned tasks.
use tokio::task::JoinHandle;
async fn do_stuff_async() -> Result<(), &'static str> {
// async work
# Err("failed")
}
async fn more_async_work() -> Result<(), &'static str> {
// more here
# Ok(())
}
async fn flatten<T>(handle: JoinHandle<Result<T, &'static str>>) -> Result<T, &'static str> {
match handle.await {
Ok(Ok(result)) => Ok(result),
Ok(Err(err)) => Err(err),
Err(err) => Err("handling failed"),
}
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let handle1 = tokio::spawn(do_stuff_async());
let handle2 = tokio::spawn(more_async_work());
match tokio::try_join!(flatten(handle1), flatten(handle2)) {
Ok(val) => {
// do something with the values
}
Err(err) => {
println!("Failed with {}.", err);
# assert_eq!(err, "failed");
}
}
# }
Using the biased; mode to control polling order.
async fn do_stuff_async() -> Result<(), &'static str> {
// async work
# Ok(())
}
async fn more_async_work() -> Result<(), &'static str> {
// more here
# Ok(())
}
# #[tokio::main(flavor = "current_thread")]
# async fn main() {
let res = tokio::try_join!(
biased;
do_stuff_async(),
more_async_work()
);
match res {
Ok((first, second)) => {
// do something with the values
}
Err(err) => {
println!("processing failed; error = {}", err);
}
}
# }
pub macro_rules! try_join {
/* macro_rules! try_join {
($(biased;)? $($future:expr),*) => { ... };
} */
}
Macro task_local
Attributes:
Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")MacroExport
Declares a new task-local key of type tokio::task::LocalKey.
Syntax
The macro wraps any number of static declarations and makes them local to the current task. Publicity and attributes for each static is preserved. For example:
Examples
# use tokio::task_local;
task_local! {
pub static ONE: u32;
#[allow(unused)]
static TWO: f32;
}
# fn main() {}
See LocalKey documentation for more
information.
pub macro_rules! task_local {
/* macro_rules! task_local {
() => { ... };
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty; $($rest:tt)*) => { ... };
($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty) => { ... };
} */
}
Re-exports
Re-export spawn
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")
pub use task::spawn;
Re-export main
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")Other("#[<cfg>(feature = \"rt-multi-thread\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")Other("#[doc(cfg(feature = \"macros\"))]")Other("#[doc(inline)]")
pub use tokio_macros::main;
Re-export test
Attributes:
Other("#[<cfg>(feature = \"rt\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"rt\")))]")Other("#[doc(cfg(feature = \"rt\"))]")Other("#[<cfg>(feature = \"rt-multi-thread\")]")Other("#[<cfg_attr>(docsrs, doc(cfg(feature = \"macros\")))]")Other("#[doc(cfg(feature = \"macros\"))]")Other("#[doc(inline)]")
pub use tokio_macros::test;