@@ -12,10 +12,11 @@ use crate::sys::sync as sys;
1212/// For more information about mutexes, check out the documentation for the poisoning variant of
1313/// this lock (which can be found at [`poison::Mutex`])
1414///
15- /// # Example
15+ /// # Examples
1616///
1717/// ```
1818/// #![feature(nonpoison_mutex)]
19+ ///
1920/// use std::sync::{Arc, nonpoison::Mutex};
2021/// use std::thread;
2122/// use std::sync::mpsc::channel;
@@ -48,6 +49,100 @@ use crate::sys::sync as sys;
4849/// rx.recv().unwrap();
4950/// ```
5051///
52+ /// Note that this `Mutex` does **not** propagate threads that panic while holding the lock via
53+ /// poisoning. If you need this functionality, see [`poison::Mutex`].
54+ ///
55+ /// ```
56+ /// #![feature(nonpoison_mutex)]
57+ ///
58+ /// use std::thread;
59+ /// use std::sync::{Arc, nonpoison::Mutex};
60+ ///
61+ /// let mutex = Arc::new(Mutex::new(0u32));
62+ /// let mut handles = Vec::new();
63+ ///
64+ /// for n in 0..10 {
65+ /// let m = Arc::clone(&mutex);
66+ /// let handle = thread::spawn(move || {
67+ /// let mut guard = m.lock();
68+ /// *guard += 1;
69+ /// panic!("panic from thread {n} {guard}")
70+ /// });
71+ /// handles.push(handle);
72+ /// }
73+ ///
74+ /// for h in handles {
75+ /// let _ = h.join();
76+ /// }
77+ ///
78+ /// println!("Finished, locked {} times", mutex.lock());
79+ /// ```
80+ ///
81+ /// To unlock a mutex guard sooner than the end of the enclosing scope,
82+ /// either create an inner scope or drop the guard manually.
83+ ///
84+ /// ```
85+ /// #![feature(nonpoison_mutex)]
86+ ///
87+ /// use std::sync::{Arc, nonpoison::Mutex};
88+ /// use std::thread;
89+ ///
90+ /// const N: usize = 3;
91+ ///
92+ /// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
93+ /// let res_mutex = Arc::new(Mutex::new(0));
94+ ///
95+ /// let mut threads = Vec::with_capacity(N);
96+ /// (0..N).for_each(|_| {
97+ /// let data_mutex_clone = Arc::clone(&data_mutex);
98+ /// let res_mutex_clone = Arc::clone(&res_mutex);
99+ ///
100+ /// threads.push(thread::spawn(move || {
101+ /// // Here we use a block to limit the lifetime of the lock guard.
102+ /// let result = {
103+ /// let mut data = data_mutex_clone.lock();
104+ /// // This is the result of some important and long-ish work.
105+ /// let result = data.iter().fold(0, |acc, x| acc + x * 2);
106+ /// data.push(result);
107+ /// result
108+ /// // The mutex guard gets dropped here, together with any other values
109+ /// // created in the critical section.
110+ /// };
111+ /// // The guard created here is a temporary dropped at the end of the statement, i.e.
112+ /// // the lock would not remain being held even if the thread did some additional work.
113+ /// *res_mutex_clone.lock() += result;
114+ /// }));
115+ /// });
116+ ///
117+ /// let mut data = data_mutex.lock();
118+ /// // This is the result of some important and long-ish work.
119+ /// let result = data.iter().fold(0, |acc, x| acc + x * 2);
120+ /// data.push(result);
121+ /// // We drop the `data` explicitly because it's not necessary anymore and the
122+ /// // thread still has work to do. This allows other threads to start working on
123+ /// // the data immediately, without waiting for the rest of the unrelated work
124+ /// // to be done here.
125+ /// //
126+ /// // It's even more important here than in the threads because we `.join` the
127+ /// // threads after that. If we had not dropped the mutex guard, a thread could
128+ /// // be waiting forever for it, causing a deadlock.
129+ /// // As in the threads, a block could have been used instead of calling the
130+ /// // `drop` function.
131+ /// drop(data);
132+ /// // Here the mutex guard is not assigned to a variable and so, even if the
133+ /// // scope does not end after this line, the mutex is still released: there is
134+ /// // no deadlock.
135+ /// *res_mutex.lock() += result;
136+ ///
137+ /// threads.into_iter().for_each(|thread| {
138+ /// thread
139+ /// .join()
140+ /// .expect("The thread creating or execution failed !")
141+ /// });
142+ ///
143+ /// assert_eq!(*res_mutex.lock(), 800);
144+ /// ```
145+ ///
51146/// [`poison::Mutex`]: crate::sync::poison::Mutex
52147#[ unstable( feature = "nonpoison_mutex" , issue = "134645" ) ]
53148#[ cfg_attr( not( test) , rustc_diagnostic_item = "NonPoisonMutex" ) ]
@@ -233,9 +328,6 @@ impl<T: ?Sized> Mutex<T> {
233328 /// If the mutex could not be acquired because it is already locked, then
234329 /// this call will return [`None`].
235330 ///
236- /// TODO(connor): This should return a `TryLockResult` as specified in
237- /// <https://github.com/rust-lang/rust/issues/134645>
238- ///
239331 /// # Examples
240332 ///
241333 /// ```
@@ -248,7 +340,7 @@ impl<T: ?Sized> Mutex<T> {
248340 ///
249341 /// thread::spawn(move || {
250342 /// let mut lock = c_mutex.try_lock();
251- /// if let Some (ref mut mutex) = lock {
343+ /// if let Ok (ref mut mutex) = lock {
252344 /// **mutex = 10;
253345 /// } else {
254346 /// println!("try_lock failed");
@@ -325,10 +417,10 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
325417 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
326418 let mut d = f. debug_struct ( "Mutex" ) ;
327419 match self . try_lock ( ) {
328- Some ( guard) => {
420+ Ok ( guard) => {
329421 d. field ( "data" , & & * guard) ;
330422 }
331- None => {
423+ Err ( WouldBlock ) => {
332424 d. field ( "data" , & format_args ! ( "<locked>" ) ) ;
333425 }
334426 }
0 commit comments