From dd3dc729876e56b643bb5795cb282a913c2a7952 Mon Sep 17 00:00:00 2001 From: CorinJG Date: Thu, 25 Mar 2021 17:51:42 +0000 Subject: [PATCH 1/3] (minor) amendments to Mutex docs To be more correct about fact that std Mutex can also be held across _some_ .await points --- tokio/src/sync/mutex.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tokio/src/sync/mutex.rs b/tokio/src/sync/mutex.rs index 2e97eb8f127..cd538d3f72d 100644 --- a/tokio/src/sync/mutex.rs +++ b/tokio/src/sync/mutex.rs @@ -10,9 +10,11 @@ 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 and the lock guard can be held -/// across await points. +/// This type acts similarly to [`std::sync::Mutex`], with two major +/// differences: [`lock`] is an async method so does not block, and the lock +/// guard is [`Send`] so can be held across any kind of `.await` point, not just +/// those which keep the task within a single thread (such as in the context of +/// a local task set or within a `join!` on the main thread, etc.) /// /// # Which kind of mutex should you use? /// @@ -123,7 +125,8 @@ pub struct Mutex { c: UnsafeCell, } -/// A handle to a held `Mutex`. +/// A handle to a held `Mutex`. The guard can be held across any `.await` point +/// as it is [`Send`]. /// /// As long as you have this guard, you have exclusive access to the underlying /// `T`. The guard internally borrows the `Mutex`, so the mutex will not be From 323ac0e3ec4693947e661426be835e60f67906ff Mon Sep 17 00:00:00 2001 From: CorinJG Date: Fri, 26 Mar 2021 12:35:11 +0000 Subject: [PATCH 2/3] sync: increase clarity regarding use of async mutex Minor edits for improved readability. Introduced an extra paragraph under 'Which kind of mutex should you use?' explicitly warning against holding std Mutex across .await points even though it's possible in some situations. --- tokio/src/sync/mutex.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tokio/src/sync/mutex.rs b/tokio/src/sync/mutex.rs index cd538d3f72d..4336702803b 100644 --- a/tokio/src/sync/mutex.rs +++ b/tokio/src/sync/mutex.rs @@ -12,23 +12,26 @@ use std::sync::Arc; /// /// This type acts similarly to [`std::sync::Mutex`], with two major /// differences: [`lock`] is an async method so does not block, and the lock -/// guard is [`Send`] so can be held across any kind of `.await` point, not just -/// those which keep the task within a single thread (such as in the context of -/// a local task set or within a `join!` on the main thread, etc.) +/// guard is designed to be held across `.await` points. /// /// # Which kind of mutex should you use? /// /// 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. +/// [`Mutex`][std] from the standard library in asynchronous code. /// -/// 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. +/// The feature that the async mutex offers over the blocking mutex is the +/// ability to keep it locked across an `.await` point, which makes the async +/// mutex more expensive than the ordinary one and is rarely necessary. The +/// primary use case for the async mutex is to provide shared mutable access to +/// IO resources such as a database connection. If the value behind the mutex is +/// just data, it's usually appropriate to use a blocking mutex such as the one +/// in the standard library or [`parking_lot`]. +/// +/// Note that, whilst the compiler will not prevent the std `Mutex` from holding +/// its guard across `.await` points in situations where the task is not movable +/// between threads, such as in the context of a local task set or within a +/// `join!` on the main thread, etc., this is unlikely to lead to correct +/// concurrent code in practice as it can easily lead to deadlocks. /// /// A common pattern is to wrap the `Arc>` in a struct that provides /// non-async methods for performing operations on the data within, and only From 122f698f3499b8e890c85d673664d3936c61c4f6 Mon Sep 17 00:00:00 2001 From: CorinJG Date: Fri, 26 Mar 2021 16:05:12 +0000 Subject: [PATCH 3/3] further edits --- tokio/src/sync/mutex.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tokio/src/sync/mutex.rs b/tokio/src/sync/mutex.rs index 4336702803b..0a118e7f824 100644 --- a/tokio/src/sync/mutex.rs +++ b/tokio/src/sync/mutex.rs @@ -20,18 +20,18 @@ use std::sync::Arc; /// [`Mutex`][std] from the standard library in asynchronous code. /// /// The feature that the async mutex offers over the blocking mutex is the -/// ability to keep it locked across an `.await` point, which makes the async -/// mutex more expensive than the ordinary one and is rarely necessary. The -/// primary use case for the async mutex is to provide shared mutable access to -/// IO resources such as a database connection. If the value behind the mutex is -/// just data, it's usually appropriate to use a blocking mutex such as the one -/// in the standard library or [`parking_lot`]. +/// ability to keep it locked across an `.await` point. This makes the async +/// mutex more expensive than the blocking mutex, so the blocking mutex should +/// be preferred in the cases where it can be used. The primary use case for the +/// async mutex is to provide shared mutable access to IO resources such as a +/// database connection. If the value behind the mutex is just data, it's +/// usually appropriate to use a blocking mutex such as the one in the standard +/// library or [`parking_lot`]. /// -/// Note that, whilst the compiler will not prevent the std `Mutex` from holding +/// Note that, although the compiler will not prevent the std `Mutex` from holding /// its guard across `.await` points in situations where the task is not movable -/// between threads, such as in the context of a local task set or within a -/// `join!` on the main thread, etc., this is unlikely to lead to correct -/// concurrent code in practice as it can easily lead to deadlocks. +/// between threads, this virtually never leads to correct concurrent code in +/// practice as it can easily lead to deadlocks. /// /// A common pattern is to wrap the `Arc>` in a struct that provides /// non-async methods for performing operations on the data within, and only