1 #[cfg(all(test, not(target_os = "emscripten")))]
4 use crate::cell::UnsafeCell;
6 use crate::ops::{Deref, DerefMut};
7 use crate::sync::{poison, LockResult, TryLockError, TryLockResult};
8 use crate::sys_common::rwlock as sys;
10 /// A reader-writer lock
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).
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.
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
28 /// <details><summary>Potential deadlock example</summary>
31 /// // Thread 1 | // Thread 2
32 /// let _rg = lock.read(); |
34 /// | let _wg = lock.write();
36 /// let _rg = lock.read(); |
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.
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.
56 /// use std::sync::RwLock;
58 /// let lock = RwLock::new(5);
60 /// // many reader locks can be held at once
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
68 /// // only one write lock may be held, however
70 /// let mut w = lock.write().unwrap();
72 /// assert_eq!(*w, 6);
73 /// } // write lock is dropped here
76 /// [`Mutex`]: super::Mutex
77 #[stable(feature = "rust1", since = "1.0.0")]
78 pub struct RwLock<T: ?Sized> {
79 inner: sys::MovableRwLock,
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> {}
89 /// RAII structure used to release the shared read access of a lock when
92 /// This structure is created by the [`read`] and [`try_read`] methods on
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 #[clippy::has_significant_drop]
103 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
105 inner_lock: &'a sys::MovableRwLock,
108 #[stable(feature = "rust1", since = "1.0.0")]
109 impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {}
111 #[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
112 unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
114 /// RAII structure used to release the exclusive write access of a lock when
117 /// This structure is created by the [`write`] and [`try_write`] methods
120 /// [`write`]: RwLock::write
121 /// [`try_write`]: RwLock::try_write
122 #[must_use = "if unused the RwLock will immediately unlock"]
123 #[must_not_suspend = "holding a RwLockWriteGuard across suspend \
124 points can cause deadlocks, delays, \
125 and cause Future's to not implement `Send`"]
126 #[stable(feature = "rust1", since = "1.0.0")]
127 #[clippy::has_significant_drop]
128 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
130 poison: poison::Guard,
133 #[stable(feature = "rust1", since = "1.0.0")]
134 impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {}
136 #[stable(feature = "rwlock_guard_sync", since = "1.23.0")]
137 unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {}
140 /// Creates a new instance of an `RwLock<T>` which is unlocked.
145 /// use std::sync::RwLock;
147 /// let lock = RwLock::new(5);
149 #[stable(feature = "rust1", since = "1.0.0")]
150 pub fn new(t: T) -> RwLock<T> {
152 inner: sys::MovableRwLock::new(),
153 poison: poison::Flag::new(),
154 data: UnsafeCell::new(t),
159 impl<T: ?Sized> RwLock<T> {
160 /// Locks this rwlock with shared read access, blocking the current thread
161 /// until it can be acquired.
163 /// The calling thread will be blocked until there are no more writers which
164 /// hold the lock. There may be other readers currently inside the lock when
165 /// this method returns. This method does not provide any guarantees with
166 /// respect to the ordering of whether contentious readers or writers will
167 /// acquire the lock first.
169 /// Returns an RAII guard which will release this thread's shared access
170 /// once it is dropped.
174 /// This function will return an error if the RwLock is poisoned. An RwLock
175 /// is poisoned whenever a writer panics while holding an exclusive lock.
176 /// The failure will occur immediately after the lock has been acquired.
180 /// This function might panic when called if the lock is already held by the current thread.
185 /// use std::sync::{Arc, RwLock};
188 /// let lock = Arc::new(RwLock::new(1));
189 /// let c_lock = Arc::clone(&lock);
191 /// let n = lock.read().unwrap();
192 /// assert_eq!(*n, 1);
194 /// thread::spawn(move || {
195 /// let r = c_lock.read();
196 /// assert!(r.is_ok());
197 /// }).join().unwrap();
200 #[stable(feature = "rust1", since = "1.0.0")]
201 pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
204 RwLockReadGuard::new(self)
208 /// Attempts to acquire this rwlock with shared read access.
210 /// If the access could not be granted at this time, then `Err` is returned.
211 /// Otherwise, an RAII guard is returned which will release the shared access
212 /// when it is dropped.
214 /// This function does not block.
216 /// This function does not provide any guarantees with respect to the ordering
217 /// of whether contentious readers or writers will acquire the lock first.
221 /// This function will return the [`Poisoned`] error if the RwLock is poisoned.
222 /// An RwLock is poisoned whenever a writer panics while holding an exclusive
223 /// lock. `Poisoned` will only be returned if the lock would have otherwise been
226 /// This function will return the [`WouldBlock`] error if the RwLock could not
227 /// be acquired because it was already locked exclusively.
229 /// [`Poisoned`]: TryLockError::Poisoned
230 /// [`WouldBlock`]: TryLockError::WouldBlock
235 /// use std::sync::RwLock;
237 /// let lock = RwLock::new(1);
239 /// match lock.try_read() {
240 /// Ok(n) => assert_eq!(*n, 1),
241 /// Err(_) => unreachable!(),
245 #[stable(feature = "rust1", since = "1.0.0")]
246 pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
248 if self.inner.try_read() {
249 Ok(RwLockReadGuard::new(self)?)
251 Err(TryLockError::WouldBlock)
256 /// Locks this rwlock with exclusive write access, blocking the current
257 /// thread until it can be acquired.
259 /// This function will not return while other writers or other readers
260 /// currently have access to the lock.
262 /// Returns an RAII guard which will drop the write access of this rwlock
267 /// This function will return an error if the RwLock is poisoned. An RwLock
268 /// is poisoned whenever a writer panics while holding an exclusive lock.
269 /// An error will be returned when the lock is acquired.
273 /// This function might panic when called if the lock is already held by the current thread.
278 /// use std::sync::RwLock;
280 /// let lock = RwLock::new(1);
282 /// let mut n = lock.write().unwrap();
285 /// assert!(lock.try_read().is_err());
288 #[stable(feature = "rust1", since = "1.0.0")]
289 pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
292 RwLockWriteGuard::new(self)
296 /// Attempts to lock this rwlock with exclusive write access.
298 /// If the lock could not be acquired at this time, then `Err` is returned.
299 /// Otherwise, an RAII guard is returned which will release the lock when
302 /// This function does not block.
304 /// This function does not provide any guarantees with respect to the ordering
305 /// of whether contentious readers or writers will acquire the lock first.
309 /// This function will return the [`Poisoned`] error if the RwLock is
310 /// poisoned. An RwLock is poisoned whenever a writer panics while holding
311 /// an exclusive lock. `Poisoned` will only be returned if the lock would have
312 /// otherwise been acquired.
314 /// This function will return the [`WouldBlock`] error if the RwLock could not
315 /// be acquired because it was already locked exclusively.
317 /// [`Poisoned`]: TryLockError::Poisoned
318 /// [`WouldBlock`]: TryLockError::WouldBlock
324 /// use std::sync::RwLock;
326 /// let lock = RwLock::new(1);
328 /// let n = lock.read().unwrap();
329 /// assert_eq!(*n, 1);
331 /// assert!(lock.try_write().is_err());
334 #[stable(feature = "rust1", since = "1.0.0")]
335 pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
337 if self.inner.try_write() {
338 Ok(RwLockWriteGuard::new(self)?)
340 Err(TryLockError::WouldBlock)
345 /// Determines whether the lock is poisoned.
347 /// If another thread is active, the lock can still become poisoned at any
348 /// time. You should not trust a `false` value for program correctness
349 /// without additional synchronization.
354 /// use std::sync::{Arc, RwLock};
357 /// let lock = Arc::new(RwLock::new(0));
358 /// let c_lock = Arc::clone(&lock);
360 /// let _ = thread::spawn(move || {
361 /// let _lock = c_lock.write().unwrap();
362 /// panic!(); // the lock gets poisoned
364 /// assert_eq!(lock.is_poisoned(), true);
367 #[stable(feature = "sync_poison", since = "1.2.0")]
368 pub fn is_poisoned(&self) -> bool {
372 /// Clear the poisoned state from a lock
374 /// If the lock is poisoned, it will remain poisoned until this function is called. This allows
375 /// recovering from a poisoned state and marking that it has recovered. For example, if the
376 /// value is overwritten by a known-good value, then the mutex can be marked as un-poisoned. Or
377 /// possibly, the value could be inspected to determine if it is in a consistent state, and if
378 /// so the poison is removed.
383 /// #![feature(mutex_unpoison)]
385 /// use std::sync::{Arc, RwLock};
388 /// let lock = Arc::new(RwLock::new(0));
389 /// let c_lock = Arc::clone(&lock);
391 /// let _ = thread::spawn(move || {
392 /// let _lock = c_lock.write().unwrap();
393 /// panic!(); // the mutex gets poisoned
396 /// assert_eq!(lock.is_poisoned(), true);
397 /// let guard = lock.write().unwrap_or_else(|mut e| {
398 /// **e.get_mut() = 1;
399 /// lock.clear_poison();
402 /// assert_eq!(lock.is_poisoned(), false);
403 /// assert_eq!(*guard, 1);
406 #[unstable(feature = "mutex_unpoison", issue = "96469")]
407 pub fn clear_poison(&self) {
411 /// Consumes this `RwLock`, returning the underlying data.
415 /// This function will return an error if the RwLock is poisoned. An RwLock
416 /// is poisoned whenever a writer panics while holding an exclusive lock. An
417 /// error will only be returned if the lock would have otherwise been
423 /// use std::sync::RwLock;
425 /// let lock = RwLock::new(String::new());
427 /// let mut s = lock.write().unwrap();
428 /// *s = "modified".to_owned();
430 /// assert_eq!(lock.into_inner().unwrap(), "modified");
432 #[stable(feature = "rwlock_into_inner", since = "1.6.0")]
433 pub fn into_inner(self) -> LockResult<T>
437 let data = self.data.into_inner();
438 poison::map_result(self.poison.borrow(), |()| data)
441 /// Returns a mutable reference to the underlying data.
443 /// Since this call borrows the `RwLock` mutably, no actual locking needs to
444 /// take place -- the mutable borrow statically guarantees no locks exist.
448 /// This function will return an error if the RwLock is poisoned. An RwLock
449 /// is poisoned whenever a writer panics while holding an exclusive lock. An
450 /// error will only be returned if the lock would have otherwise been
456 /// use std::sync::RwLock;
458 /// let mut lock = RwLock::new(0);
459 /// *lock.get_mut().unwrap() = 10;
460 /// assert_eq!(*lock.read().unwrap(), 10);
462 #[stable(feature = "rwlock_get_mut", since = "1.6.0")]
463 pub fn get_mut(&mut self) -> LockResult<&mut T> {
464 let data = self.data.get_mut();
465 poison::map_result(self.poison.borrow(), |()| data)
469 #[stable(feature = "rust1", since = "1.0.0")]
470 impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 let mut d = f.debug_struct("RwLock");
473 match self.try_read() {
475 d.field("data", &&*guard);
477 Err(TryLockError::Poisoned(err)) => {
478 d.field("data", &&**err.get_ref());
480 Err(TryLockError::WouldBlock) => {
481 struct LockedPlaceholder;
482 impl fmt::Debug for LockedPlaceholder {
483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 f.write_str("<locked>")
487 d.field("data", &LockedPlaceholder);
490 d.field("poisoned", &self.poison.get());
491 d.finish_non_exhaustive()
495 #[stable(feature = "rw_lock_default", since = "1.10.0")]
496 impl<T: Default> Default for RwLock<T> {
497 /// Creates a new `RwLock<T>`, with the `Default` value for T.
498 fn default() -> RwLock<T> {
499 RwLock::new(Default::default())
503 #[stable(feature = "rw_lock_from", since = "1.24.0")]
504 impl<T> From<T> for RwLock<T> {
505 /// Creates a new instance of an `RwLock<T>` which is unlocked.
506 /// This is equivalent to [`RwLock::new`].
507 fn from(t: T) -> Self {
512 impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> {
513 unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockReadGuard<'rwlock, T>> {
514 poison::map_result(lock.poison.borrow(), |()| RwLockReadGuard {
515 inner_lock: &lock.inner,
516 data: lock.data.get(),
521 impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> {
522 unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> {
523 poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard })
527 #[stable(feature = "std_debug", since = "1.16.0")]
528 impl<T: fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> {
529 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
534 #[stable(feature = "std_guard_impls", since = "1.20.0")]
535 impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> {
536 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
541 #[stable(feature = "std_debug", since = "1.16.0")]
542 impl<T: fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> {
543 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
548 #[stable(feature = "std_guard_impls", since = "1.20.0")]
549 impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> {
550 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555 #[stable(feature = "rust1", since = "1.0.0")]
556 impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> {
559 fn deref(&self) -> &T {
560 unsafe { &*self.data }
564 #[stable(feature = "rust1", since = "1.0.0")]
565 impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> {
568 fn deref(&self) -> &T {
569 unsafe { &*self.lock.data.get() }
573 #[stable(feature = "rust1", since = "1.0.0")]
574 impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> {
575 fn deref_mut(&mut self) -> &mut T {
576 unsafe { &mut *self.lock.data.get() }
580 #[stable(feature = "rust1", since = "1.0.0")]
581 impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> {
584 self.inner_lock.read_unlock();
589 #[stable(feature = "rust1", since = "1.0.0")]
590 impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> {
592 self.lock.poison.done(&self.poison);
594 self.lock.inner.write_unlock();