@@ -420,7 +420,7 @@ impl<T: ?Sized> RwLock<T> {
420
420
///
421
421
/// // Drop the guard after the spawned task finishes.
422
422
/// drop(n);
423
- ///}
423
+ /// }
424
424
/// ```
425
425
pub async fn read ( & self ) -> RwLockReadGuard < ' _ , T > {
426
426
#[ cfg( all( tokio_unstable, feature = "tracing" ) ) ]
@@ -459,6 +459,58 @@ impl<T: ?Sized> RwLock<T> {
459
459
}
460
460
}
461
461
462
+ /// Blockingly locks this `RwLock` with shared read access.
463
+ ///
464
+ /// This method is intended for use cases where you
465
+ /// need to use this rwlock in asynchronous code as well as in synchronous code.
466
+ ///
467
+ /// Returns an RAII guard which will drop the read access of this `RwLock` when dropped.
468
+ ///
469
+ /// # Panics
470
+ ///
471
+ /// This function panics if called within an asynchronous execution context.
472
+ ///
473
+ /// - If you find yourself in an asynchronous execution context and needing
474
+ /// to call some (synchronous) function which performs one of these
475
+ /// `blocking_` operations, then consider wrapping that call inside
476
+ /// [`spawn_blocking()`][crate::runtime::Handle::spawn_blocking]
477
+ /// (or [`block_in_place()`][crate::task::block_in_place]).
478
+ ///
479
+ /// # Examples
480
+ ///
481
+ /// ```
482
+ /// use std::sync::Arc;
483
+ /// use tokio::sync::RwLock;
484
+ ///
485
+ /// #[tokio::main]
486
+ /// async fn main() {
487
+ /// let rwlock = Arc::new(RwLock::new(1));
488
+ /// let mut write_lock = rwlock.write().await;
489
+ ///
490
+ /// let blocking_task = tokio::task::spawn_blocking({
491
+ /// let rwlock = Arc::clone(&rwlock);
492
+ /// move || {
493
+ /// // This shall block until the `write_lock` is released.
494
+ /// let read_lock = rwlock.blocking_read();
495
+ /// assert_eq!(*read_lock, 0);
496
+ /// }
497
+ /// });
498
+ ///
499
+ /// *write_lock -= 1;
500
+ /// drop(write_lock); // release the lock.
501
+ ///
502
+ /// // Await the completion of the blocking task.
503
+ /// blocking_task.await.unwrap();
504
+ ///
505
+ /// // Assert uncontended.
506
+ /// assert!(rwlock.try_write().is_ok());
507
+ /// }
508
+ /// ```
509
+ #[ cfg( feature = "sync" ) ]
510
+ pub fn blocking_read ( & self ) -> RwLockReadGuard < ' _ , T > {
511
+ crate :: future:: block_on ( self . read ( ) )
512
+ }
513
+
462
514
/// Locks this `RwLock` with shared read access, causing the current task
463
515
/// to yield until the lock has been acquired.
464
516
///
@@ -739,6 +791,60 @@ impl<T: ?Sized> RwLock<T> {
739
791
}
740
792
}
741
793
794
+ /// Blockingly locks this `RwLock` with exclusive write access.
795
+ ///
796
+ /// This method is intended for use cases where you
797
+ /// need to use this rwlock in asynchronous code as well as in synchronous code.
798
+ ///
799
+ /// Returns an RAII guard which will drop the write access of this `RwLock` when dropped.
800
+ ///
801
+ /// # Panics
802
+ ///
803
+ /// This function panics if called within an asynchronous execution context.
804
+ ///
805
+ /// - If you find yourself in an asynchronous execution context and needing
806
+ /// to call some (synchronous) function which performs one of these
807
+ /// `blocking_` operations, then consider wrapping that call inside
808
+ /// [`spawn_blocking()`][crate::runtime::Handle::spawn_blocking]
809
+ /// (or [`block_in_place()`][crate::task::block_in_place]).
810
+ ///
811
+ /// # Examples
812
+ ///
813
+ /// ```
814
+ /// use std::sync::Arc;
815
+ /// use tokio::{sync::RwLock};
816
+ ///
817
+ /// #[tokio::main]
818
+ /// async fn main() {
819
+ /// let rwlock = Arc::new(RwLock::new(1));
820
+ /// let read_lock = rwlock.read().await;
821
+ ///
822
+ /// let blocking_task = tokio::task::spawn_blocking({
823
+ /// let rwlock = Arc::clone(&rwlock);
824
+ /// move || {
825
+ /// // This shall block until the `read_lock` is released.
826
+ /// let mut write_lock = rwlock.blocking_write();
827
+ /// *write_lock = 2;
828
+ /// }
829
+ /// });
830
+ ///
831
+ /// assert_eq!(*read_lock, 1);
832
+ /// // Release the last outstanding read lock.
833
+ /// drop(read_lock);
834
+ ///
835
+ /// // Await the completion of the blocking task.
836
+ /// blocking_task.await.unwrap();
837
+ ///
838
+ /// // Assert uncontended.
839
+ /// let read_lock = rwlock.try_read().unwrap();
840
+ /// assert_eq!(*read_lock, 2);
841
+ /// }
842
+ /// ```
843
+ #[ cfg( feature = "sync" ) ]
844
+ pub fn blocking_write ( & self ) -> RwLockWriteGuard < ' _ , T > {
845
+ crate :: future:: block_on ( self . write ( ) )
846
+ }
847
+
742
848
/// Locks this `RwLock` with exclusive write access, causing the current
743
849
/// task to yield until the lock has been acquired.
744
850
///
0 commit comments