]> git.lizzy.rs Git - rust.git/blob - library/std/src/sync/rwlock.rs
ed62fa977becab7b56065382c333d2b945b8b5b4
[rust.git] / library / std / src / sync / rwlock.rs
1 #[cfg(all(test, not(target_os = "emscripten")))]
2 mod tests;
3
4 use crate::cell::UnsafeCell;
5 use crate::fmt;
6 use crate::ops::{Deref, DerefMut};
7 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
8 use crate::sys_common::rwlock as sys;
9
10 /// A reader-writer lock
11 ///
12 /// This type of lock allows a number of readers or at most one writer at any
13 /// point in time. The write portion of this lock typically allows modification
14 /// of the underlying data (exclusive access) and the read portion of this lock
15 /// typically allows for read-only access (shared access).
16 ///
17 /// In comparison, a [`Mutex`] does not distinguish between readers or writers
18 /// that acquire the lock, therefore blocking any threads waiting for the lock to
19 /// become available. An `RwLock` will allow any number of readers to acquire the
20 /// lock as long as a writer is not holding the lock.
21 ///
22 /// The priority policy of the lock is dependent on the underlying operating
23 /// system's implementation, and this type does not guarantee that any
24 /// particular policy will be used. In particular, a writer which is waiting to
25 /// acquire the lock in `write` might or might not block concurrent calls to
26 /// `read`, e.g.:
27 ///
28 /// <details><summary>Potential deadlock example</summary>
29 ///
30 /// ```text
31 /// // Thread 1             |  // Thread 2
32 /// let _rg = lock.read();  |
33 ///                         |  // will block
34 ///                         |  let _wg = lock.write();
35 /// // may deadlock         |
36 /// let _rg = lock.read();  |
37 /// ```
38 /// </details>
39 ///
40 /// The type parameter `T` represents the data that this lock protects. It is
41 /// required that `T` satisfies [`Send`] to be shared across threads and
42 /// [`Sync`] to allow concurrent access through readers. The RAII guards
43 /// returned from the locking methods implement [`Deref`] (and [`DerefMut`]
44 /// for the `write` methods) to allow access to the content of the lock.
45 ///
46 /// # Poisoning
47 ///
48 /// An `RwLock`, like [`Mutex`], will become poisoned on a panic. Note, however,
49 /// that an `RwLock` may only be poisoned if a panic occurs while it is locked
50 /// exclusively (write mode). If a panic occurs in any reader, then the lock
51 /// will not be poisoned.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use std::sync::RwLock;
57 ///
58 /// let lock = RwLock::new(5);
59 ///
60 /// // many reader locks can be held at once
61 /// {
62 ///     let r1 = lock.read().unwrap();
63 ///     let r2 = lock.read().unwrap();
64 ///     assert_eq!(*r1, 5);
65 ///     assert_eq!(*r2, 5);
66 /// } // read locks are dropped at this point
67 ///
68 /// // only one write lock may be held, however
69 /// {
70 ///     let mut w = lock.write().unwrap();
71 ///     *w += 1;
72 ///     assert_eq!(*w, 6);
73 /// } // write lock is dropped here
74 /// ```
75 ///
76 /// [`Mutex`]: super::Mutex
77 #[stable(feature = "rust1", since = "1.0.0")]
78 pub struct RwLock<T: ?Sized> {
79     inner: sys::MovableRwLock,
80     poison: poison::Flag,
81     data: UnsafeCell<T>,
82 }
83
84 #[stable(feature = "rust1", since = "1.0.0")]
85 unsafe impl<T: ?Sized + Send> Send for RwLock<T> {}
86 #[stable(feature = "rust1", since = "1.0.0")]
87 unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
88
89 /// RAII structure used to release the shared read access of a lock when
90 /// dropped.
91 ///
92 /// This structure is created by the [`read`] and [`try_read`] methods on
93 /// [`RwLock`].
94 ///
95 /// [`read`]: RwLock::read
96 /// [`try_read`]: RwLock::try_read
97 #[must_use = "if unused the RwLock will immediately unlock"]
98 #[must_not_suspend = "holding a RwLockReadGuard across suspend \
99                       points can cause deadlocks, delays, \
100                       and cause Futures to not implement `Send`"]
101 #[stable(feature = "rust1", since = "1.0.0")]
102 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
103     lock: &'a RwLock<T>,
104 }
105
106 #[stable(feature = "rust1", since = "1.0.0")]
107 impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {}
108
109 #[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
110 unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
111
112 /// RAII structure used to release the exclusive write access of a lock when
113 /// dropped.
114 ///
115 /// This structure is created by the [`write`] and [`try_write`] methods
116 /// on [`RwLock`].
117 ///
118 /// [`write`]: RwLock::write
119 /// [`try_write`]: RwLock::try_write
120 #[must_use = "if unused the RwLock will immediately unlock"]
121 #[must_not_suspend = "holding a RwLockWriteGuard across suspend \
122                       points can cause deadlocks, delays, \
123                       and cause Future's to not implement `Send`"]
124 #[stable(feature = "rust1", since = "1.0.0")]
125 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
126     lock: &'a RwLock<T>,
127     poison: poison::Guard,
128 }
129
130 #[stable(feature = "rust1", since = "1.0.0")]
131 impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
132
133 #[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
134 unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
135
136 impl<T> RwLock<T> {
137     /// Creates a new instance of an `RwLock<T>` which is unlocked.
138     ///
139     /// # Examples
140     ///
141     /// ```
142     /// use std::sync::RwLock;
143     ///
144     /// let lock = RwLock::new(5);
145     /// ```
146     #[stable(feature = "rust1", since = "1.0.0")]
147     pub fn new(t: T) -> RwLock<T> {
148         RwLock {
149             inner: sys::MovableRwLock::new(),
150             poison: poison::Flag::new(),
151             data: UnsafeCell::new(t),
152         }
153     }
154 }
155
156 impl<T: ?Sized> RwLock<T> {
157     /// Locks this rwlock with shared read access, blocking the current thread
158     /// until it can be acquired.
159     ///
160     /// The calling thread will be blocked until there are no more writers which
161     /// hold the lock. There may be other readers currently inside the lock when
162     /// this method returns. This method does not provide any guarantees with
163     /// respect to the ordering of whether contentious readers or writers will
164     /// acquire the lock first.
165     ///
166     /// Returns an RAII guard which will release this thread's shared access
167     /// once it is dropped.
168     ///
169     /// # Errors
170     ///
171     /// This function will return an error if the RwLock is poisoned. An RwLock
172     /// is poisoned whenever a writer panics while holding an exclusive lock.
173     /// The failure will occur immediately after the lock has been acquired.
174     ///
175     /// # Panics
176     ///
177     /// This function might panic when called if the lock is already held by the current thread.
178     ///
179     /// # Examples
180     ///
181     /// ```
182     /// use std::sync::{Arc, RwLock};
183     /// use std::thread;
184     ///
185     /// let lock = Arc::new(RwLock::new(1));
186     /// let c_lock = Arc::clone(&lock);
187     ///
188     /// let n = lock.read().unwrap();
189     /// assert_eq!(*n, 1);
190     ///
191     /// thread::spawn(move || {
192     ///     let r = c_lock.read();
193     ///     assert!(r.is_ok());
194     /// }).join().unwrap();
195     /// ```
196     #[inline]
197     #[stable(feature = "rust1", since = "1.0.0")]
198     pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
199         unsafe {
200             self.inner.read();
201             RwLockReadGuard::new(self)
202         }
203     }
204
205     /// Attempts to acquire this rwlock with shared read access.
206     ///
207     /// If the access could not be granted at this time, then `Err` is returned.
208     /// Otherwise, an RAII guard is returned which will release the shared access
209     /// when it is dropped.
210     ///
211     /// This function does not block.
212     ///
213     /// This function does not provide any guarantees with respect to the ordering
214     /// of whether contentious readers or writers will acquire the lock first.
215     ///
216     /// # Errors
217     ///
218     /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
219     /// An RwLock is poisoned whenever a writer panics while holding an exclusive
220     /// lock. `Poisoned` will only be returned if the lock would have otherwise been
221     /// acquired.
222     ///
223     /// This function will return the [`WouldBlock`] error if the RwLock could not
224     /// be acquired because it was already locked exclusively.
225     ///
226     /// [`Poisoned`]: TryLockError::Poisoned
227     /// [`WouldBlock`]: TryLockError::WouldBlock
228     ///
229     /// # Examples
230     ///
231     /// ```
232     /// use std::sync::RwLock;
233     ///
234     /// let lock = RwLock::new(1);
235     ///
236     /// match lock.try_read() {
237     ///     Ok(n) => assert_eq!(*n, 1),
238     ///     Err(_) => unreachable!(),
239     /// };
240     /// ```
241     #[inline]
242     #[stable(feature = "rust1", since = "1.0.0")]
243     pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
244         unsafe {
245             if self.inner.try_read() {
246                 Ok(RwLockReadGuard::new(self)?)
247             } else {
248                 Err(TryLockError::WouldBlock)
249             }
250         }
251     }
252
253     /// Locks this rwlock with exclusive write access, blocking the current
254     /// thread until it can be acquired.
255     ///
256     /// This function will not return while other writers or other readers
257     /// currently have access to the lock.
258     ///
259     /// Returns an RAII guard which will drop the write access of this rwlock
260     /// when dropped.
261     ///
262     /// # Errors
263     ///
264     /// This function will return an error if the RwLock is poisoned. An RwLock
265     /// is poisoned whenever a writer panics while holding an exclusive lock.
266     /// An error will be returned when the lock is acquired.
267     ///
268     /// # Panics
269     ///
270     /// This function might panic when called if the lock is already held by the current thread.
271     ///
272     /// # Examples
273     ///
274     /// ```
275     /// use std::sync::RwLock;
276     ///
277     /// let lock = RwLock::new(1);
278     ///
279     /// let mut n = lock.write().unwrap();
280     /// *n = 2;
281     ///
282     /// assert!(lock.try_read().is_err());
283     /// ```
284     #[inline]
285     #[stable(feature = "rust1", since = "1.0.0")]
286     pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
287         unsafe {
288             self.inner.write();
289             RwLockWriteGuard::new(self)
290         }
291     }
292
293     /// Attempts to lock this rwlock with exclusive write access.
294     ///
295     /// If the lock could not be acquired at this time, then `Err` is returned.
296     /// Otherwise, an RAII guard is returned which will release the lock when
297     /// it is dropped.
298     ///
299     /// This function does not block.
300     ///
301     /// This function does not provide any guarantees with respect to the ordering
302     /// of whether contentious readers or writers will acquire the lock first.
303     ///
304     /// # Errors
305     ///
306     /// This function will return the [`Poisoned`] error if the RwLock is
307     /// poisoned. An RwLock is poisoned whenever a writer panics while holding
308     /// an exclusive lock. `Poisoned` will only be returned if the lock would have
309     /// otherwise been acquired.
310     ///
311     /// This function will return the [`WouldBlock`] error if the RwLock could not
312     /// be acquired because it was already locked exclusively.
313     ///
314     /// [`Poisoned`]: TryLockError::Poisoned
315     /// [`WouldBlock`]: TryLockError::WouldBlock
316     ///
317     ///
318     /// # Examples
319     ///
320     /// ```
321     /// use std::sync::RwLock;
322     ///
323     /// let lock = RwLock::new(1);
324     ///
325     /// let n = lock.read().unwrap();
326     /// assert_eq!(*n, 1);
327     ///
328     /// assert!(lock.try_write().is_err());
329     /// ```
330     #[inline]
331     #[stable(feature = "rust1", since = "1.0.0")]
332     pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
333         unsafe {
334             if self.inner.try_write() {
335                 Ok(RwLockWriteGuard::new(self)?)
336             } else {
337                 Err(TryLockError::WouldBlock)
338             }
339         }
340     }
341
342     /// Determines whether the lock is poisoned.
343     ///
344     /// If another thread is active, the lock can still become poisoned at any
345     /// time. You should not trust a `false` value for program correctness
346     /// without additional synchronization.
347     ///
348     /// # Examples
349     ///
350     /// ```
351     /// use std::sync::{Arc, RwLock};
352     /// use std::thread;
353     ///
354     /// let lock = Arc::new(RwLock::new(0));
355     /// let c_lock = Arc::clone(&lock);
356     ///
357     /// let _ = thread::spawn(move || {
358     ///     let _lock = c_lock.write().unwrap();
359     ///     panic!(); // the lock gets poisoned
360     /// }).join();
361     /// assert_eq!(lock.is_poisoned(), true);
362     /// ```
363     #[inline]
364     #[stable(feature = "sync_poison", since = "1.2.0")]
365     pub fn is_poisoned(&self) -> bool {
366         self.poison.get()
367     }
368
369     /// Consumes this `RwLock`, returning the underlying data.
370     ///
371     /// # Errors
372     ///
373     /// This function will return an error if the RwLock is poisoned. An RwLock
374     /// is poisoned whenever a writer panics while holding an exclusive lock. An
375     /// error will only be returned if the lock would have otherwise been
376     /// acquired.
377     ///
378     /// # Examples
379     ///
380     /// ```
381     /// use std::sync::RwLock;
382     ///
383     /// let lock = RwLock::new(String::new());
384     /// {
385     ///     let mut s = lock.write().unwrap();
386     ///     *s = "modified".to_owned();
387     /// }
388     /// assert_eq!(lock.into_inner().unwrap(), "modified");
389     /// ```
390     #[stable(feature = "rwlock_into_inner", since = "1.6.0")]
391     pub fn into_inner(self) -> LockResult<T>
392     where
393         T: Sized,
394     {
395         let data = self.data.into_inner();
396         poison::map_result(self.poison.borrow(), |_| data)
397     }
398
399     /// Returns a mutable reference to the underlying data.
400     ///
401     /// Since this call borrows the `RwLock` mutably, no actual locking needs to
402     /// take place -- the mutable borrow statically guarantees no locks exist.
403     ///
404     /// # Errors
405     ///
406     /// This function will return an error if the RwLock is poisoned. An RwLock
407     /// is poisoned whenever a writer panics while holding an exclusive lock. An
408     /// error will only be returned if the lock would have otherwise been
409     /// acquired.
410     ///
411     /// # Examples
412     ///
413     /// ```
414     /// use std::sync::RwLock;
415     ///
416     /// let mut lock = RwLock::new(0);
417     /// *lock.get_mut().unwrap() = 10;
418     /// assert_eq!(*lock.read().unwrap(), 10);
419     /// ```
420     #[stable(feature = "rwlock_get_mut", since = "1.6.0")]
421     pub fn get_mut(&mut self) -> LockResult<&mut T> {
422         let data = self.data.get_mut();
423         poison::map_result(self.poison.borrow(), |_| data)
424     }
425 }
426
427 #[stable(feature = "rust1", since = "1.0.0")]
428 impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
429     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430         let mut d = f.debug_struct("RwLock");
431         match self.try_read() {
432             Ok(guard) => {
433                 d.field("data", &&*guard);
434             }
435             Err(TryLockError::Poisoned(err)) => {
436                 d.field("data", &&**err.get_ref());
437             }
438             Err(TryLockError::WouldBlock) => {
439                 struct LockedPlaceholder;
440                 impl fmt::Debug for LockedPlaceholder {
441                     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
442                         f.write_str("<locked>")
443                     }
444                 }
445                 d.field("data", &LockedPlaceholder);
446             }
447         }
448         d.field("poisoned", &self.poison.get());
449         d.finish_non_exhaustive()
450     }
451 }
452
453 #[stable(feature = "rw_lock_default", since = "1.10.0")]
454 impl<T: Default> Default for RwLock<T> {
455     /// Creates a new `RwLock<T>`, with the `Default` value for T.
456     fn default() -> RwLock<T> {
457         RwLock::new(Default::default())
458     }
459 }
460
461 #[stable(feature = "rw_lock_from", since = "1.24.0")]
462 impl<T> From<T> for RwLock<T> {
463     /// Creates a new instance of an `RwLock<T>` which is unlocked.
464     /// This is equivalent to [`RwLock::new`].
465     fn from(t: T) -> Self {
466         RwLock::new(t)
467     }
468 }
469
470 impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
471     unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
472         poison::map_result(lock.poison.borrow(), |_| RwLockReadGuard { lock })
473     }
474 }
475
476 impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
477     unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> {
478         poison::map_result(lock.poison.borrow(), |guard| RwLockWriteGuard { lock, poison: guard })
479     }
480 }
481
482 #[stable(feature = "std_debug", since = "1.16.0")]
483 impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
484     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
485         (**self).fmt(f)
486     }
487 }
488
489 #[stable(feature = "std_guard_impls", since = "1.20.0")]
490 impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> {
491     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
492         (**self).fmt(f)
493     }
494 }
495
496 #[stable(feature = "std_debug", since = "1.16.0")]
497 impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
498     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
499         (**self).fmt(f)
500     }
501 }
502
503 #[stable(feature = "std_guard_impls", since = "1.20.0")]
504 impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
505     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
506         (**self).fmt(f)
507     }
508 }
509
510 #[stable(feature = "rust1", since = "1.0.0")]
511 impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
512     type Target = T;
513
514     fn deref(&self) -> &T {
515         unsafe { &*self.lock.data.get() }
516     }
517 }
518
519 #[stable(feature = "rust1", since = "1.0.0")]
520 impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
521     type Target = T;
522
523     fn deref(&self) -> &T {
524         unsafe { &*self.lock.data.get() }
525     }
526 }
527
528 #[stable(feature = "rust1", since = "1.0.0")]
529 impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
530     fn deref_mut(&mut self) -> &mut T {
531         unsafe { &mut *self.lock.data.get() }
532     }
533 }
534
535 #[stable(feature = "rust1", since = "1.0.0")]
536 impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
537     fn drop(&mut self) {
538         unsafe {
539             self.lock.inner.read_unlock();
540         }
541     }
542 }
543
544 #[stable(feature = "rust1", since = "1.0.0")]
545 impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
546     fn drop(&mut self) {
547         self.lock.poison.done(&self.poison);
548         unsafe {
549             self.lock.inner.write_unlock();
550         }
551     }
552 }