Skip to content

Add section regarding which kind of mutex to use #2658

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 20, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions tokio/src/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,35 @@ use std::sync::Arc;
/// An asynchronous `Mutex`-like type.
///
/// This type acts similarly to an asynchronous [`std::sync::Mutex`], with one
/// major difference: [`lock`] does not block. Another difference is that the
/// lock guard can be held across await points.
/// major difference: [`lock`] does not block and the lock guard can be held
/// across await points.
///
/// There are some situations where you should prefer the mutex from the
/// standard library. Generally this is the case if:
/// # Which kind of mutex should you use?
///
/// 1. The lock does not need to be held across await points.
/// 2. The duration of any single lock is near-instant.
/// Contrary to popular belief, it is ok and often preferred to use the ordinary
/// [`Mutex`][std] from the standard library in asynchronous code. This section
/// will help you decide on which kind of mutex you should use.
///
/// On the other hand, the Tokio mutex is for the situation where the lock
/// needs to be held for longer periods of time, or across await points.
/// The primary use case of the async mutex is to provide shared mutable access
/// to IO resources such as a database connection. If the data stored behind the
/// mutex is just data, it is often better to use a blocking mutex such as the
/// one in the standard library or [`parking_lot`]. This is because the feature
/// that the async mutex offers over the blocking mutex is that it is possible
/// to keep the mutex locked across an `.await` point, which is rarely necessary
/// for data.
///
/// A common pattern is to wrap the `Arc<Mutex<...>>` in a struct that provides
/// non-async methods for performing operations on the data within, and only
/// lock the mutex inside these methods. The [mini-redis] example provides an
/// illustration of this pattern.
///
/// Additionally, when you _do_ want shared access to an IO resource, it is
/// often better to spawn a task to manage the IO resource, and to use message
/// passing to communicate with that task.
Comment on lines +34 to +36
Copy link

@hberntsen hberntsen Jul 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Darksonn Could you elaborate on why message passing is often better? I'm facing this design decision in an application I'm writing.

I'm reading/writing to a TCP socket. For reading I see that message passing is the way to go because I need to route messages to different tasks. For writing to the socket I do not need an intermediary stage; it would be fine for me to lock the WriteHalf of the socket and do an async write to it from the task.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my experience, using an actor-based design when faced with this issue usually makes the code easier to reason about. That said, putting the write half in a mutex could make sense too.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thank you for your quick response 😄

///
/// [std]: std::sync::Mutex
/// [`parking_lot`]: https://docs.rs/parking_lot
/// [mini-redis]: https://github.com/tokio-rs/mini-redis/blob/master/src/db.rs
///
/// # Examples:
///
Expand Down