@@ -12,10 +12,11 @@ use crate::sys::sync as sys;
12
12
/// For more information about mutexes, check out the documentation for the poisoning variant of
13
13
/// this lock (which can be found at [`poison::Mutex`])
14
14
///
15
- /// # Example
15
+ /// # Examples
16
16
///
17
17
/// ```
18
18
/// #![feature(nonpoison_mutex)]
19
+ ///
19
20
/// use std::sync::{Arc, nonpoison::Mutex};
20
21
/// use std::thread;
21
22
/// use std::sync::mpsc::channel;
@@ -48,6 +49,100 @@ use crate::sys::sync as sys;
48
49
/// rx.recv().unwrap();
49
50
/// ```
50
51
///
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
+ ///
51
146
/// [`poison::Mutex`]: crate::sync::poison::Mutex
52
147
#[ unstable( feature = "nonpoison_mutex" , issue = "134645" ) ]
53
148
#[ cfg_attr( not( test) , rustc_diagnostic_item = "NonPoisonMutex" ) ]
@@ -233,9 +328,6 @@ impl<T: ?Sized> Mutex<T> {
233
328
/// If the mutex could not be acquired because it is already locked, then
234
329
/// this call will return [`None`].
235
330
///
236
- /// TODO(connor): This should return a `TryLockResult` as specified in
237
- /// <https://github.com/rust-lang/rust/issues/134645>
238
- ///
239
331
/// # Examples
240
332
///
241
333
/// ```
@@ -248,7 +340,7 @@ impl<T: ?Sized> Mutex<T> {
248
340
///
249
341
/// thread::spawn(move || {
250
342
/// let mut lock = c_mutex.try_lock();
251
- /// if let Some (ref mut mutex) = lock {
343
+ /// if let Ok (ref mut mutex) = lock {
252
344
/// **mutex = 10;
253
345
/// } else {
254
346
/// println!("try_lock failed");
@@ -325,10 +417,10 @@ impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
325
417
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
326
418
let mut d = f. debug_struct ( "Mutex" ) ;
327
419
match self . try_lock ( ) {
328
- Some ( guard) => {
420
+ Ok ( guard) => {
329
421
d. field ( "data" , & & * guard) ;
330
422
}
331
- None => {
423
+ Err ( WouldBlock ) => {
332
424
d. field ( "data" , & format_args ! ( "<locked>" ) ) ;
333
425
}
334
426
}
0 commit comments