sync: improve doc on blocking mutex
@@ -10,23 +10,28 @@ 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 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.
-///
-/// 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.
+/// [`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. 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, 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, 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<Mutex<...>>` in a struct that provides
/// non-async methods for performing operations on the data within, and only
@@ -123,7 +128,8 @@ pub struct Mutex<T: ?Sized> {
c: UnsafeCell<T>,
}
-/// 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
