Структура RwLock
pub struct RwLock<T: ?Sized> { /* private fields */ }
sync.Асинхронная блокировка чтения-записи.
Этот тип блокировки позволяет одновременно иметь несколько читателей или не более одного писателя. Часть блокировки для записи обычно позволяет изменять защищённые данные (эксклюзивный доступ), а часть для чтения обычно предоставляет доступ только для чтения (совместный доступ).
В отличие от неё, Mutex не различает читателей и писателей, получающих блокировку, поэтому любые задачи, ожидающие освобождения блокировки, будут приостановлены. RwLock позволяет получить блокировку любому числу читателей, если её не удерживает писатель.
Политика приоритетов блокировки чтения-записи Tokio является справедливой (или предпочитающей запись), чтобы читатели не могли бесконечно задерживать писателей. Справедливость обеспечивается очередью задач, ожидающих блокировку, по принципу «первым пришёл — первым обслужен»: блокировка для чтения не будет выдана, пока не будут получены и освобождены все запросы на блокировку для записи, поставленные в очередь до неё. Это отличается от std::sync::RwLock стандартной библиотеки Rust, где политика приоритетов зависит от реализации операционной системы.
Параметр типа T представляет данные, защищённые этой блокировкой. Для совместного использования между потоками требуется, чтобы T удовлетворял Send. RAII-стражи, возвращаемые методами блокировки, реализуют Deref (а для методов write — DerefMut), что позволяет получать доступ к содержимому блокировки.
Примеры
use tokio::sync::RwLock;
let lock = RwLock::new(5);
// many reader locks can be held at once
{
let r1 = lock.read().await;
let r2 = lock.read().await;
assert_eq!(*r1, 5);
assert_eq!(*r2, 5);
} // read locks are dropped at this point
// only one write lock may be held, however
{
let mut w = lock.write().await;
*w += 1;
assert_eq!(*w, 6);
} // write lock is dropped hereРеализации
impl<T: ?Sized> RwLock<T>
pub fn new(value: T) -> RwLock<T>where T: Sized,
Создаёт новый экземпляр RwLock<T>, который не заблокирован.
Примеры
use tokio::sync::RwLock;
let lock = RwLock::new(5);pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>where T: Sized,
Создаёт новый экземпляр RwLock<T>, который не заблокирован и допускает не более max_reads параллельных читателей.
Примеры
use tokio::sync::RwLock;
let lock = RwLock::with_max_readers(5, 1024);Паника
Вызывает панику, если max_reads равен 0 или превышает u32::MAX >> 3.
pub const fn const_new(value: T) -> RwLock<T>where T: Sized,
Создаёт новый экземпляр RwLock<T>, который не заблокирован.
При использовании нестабильной функции tracing объект RwLock, созданный с помощью const_new, не будет инструментирован. Поэтому он не будет виден в tokio-console. Вместо этого, если требуется инструментированный объект, следует использовать RwLock::new.
Примеры
use tokio::sync::RwLock;
static LOCK: RwLock<i32> = RwLock::const_new(5);pub const fn const_with_max_readers(value: T, max_reads: u32) -> RwLock<T>where T: Sized,
Создаёт новый экземпляр RwLock<T>, который не заблокирован и допускает не более max_reads параллельных читателей.
Примеры
use tokio::sync::RwLock;
static LOCK: RwLock<i32> = RwLock::const_with_max_readers(5, 1024);Паника
Вызывает панику, если max_reads равен 0 или превышает u32::MAX >> 3.
pub async fn read(&self) -> RwLockReadGuard<'_, T>
Блокирует этот RwLock для совместного чтения, приостанавливая выполнение текущей задачи до получения блокировки.
Вызывающая задача будет приостановлена, пока блокировку удерживают писатели. Когда задача возобновится, внутри блокировки могут находиться другие читатели.
Обратите внимание: согласно политике приоритетов RwLock, блокировки на чтение не предоставляются до выполнения ранее запрошенных блокировок на запись, чтобы предотвратить голодание. Поэтому может возникнуть взаимная блокировка, если текущая задача удерживает блокировку на чтение, затем пытается получить блокировку на запись, а после этого снова пытается получить блокировку на чтение.
Возвращает RAII-охранник, при удалении которого снимается блокировка на чтение этого RwLock.
Безопасность при отмене
Этот метод использует очередь для справедливого распределения блокировок в порядке их запроса. При отмене вызова read вы теряете своё место в очереди.
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let n = lock.read().await;
assert_eq!(*n, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let r = c_lock.read().await;
assert_eq!(*r, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard after the spawned task finishes.
drop(n);pub fn blocking_read(&self) -> RwLockReadGuard<'_, T>
Блокирующим образом устанавливает блокировку на чтение этого RwLock.
Этот метод предназначен для случаев, когда rwlock необходимо использовать как в асинхронном, так и в синхронном коде.
Возвращает RAII-охранник, при удалении которого снимается блокировка на чтение этого RwLock.
Паника
Эта функция вызывает панику, если её вызвать в контексте асинхронного выполнения.
- Если вам нужно в контексте асинхронного выполнения вызвать синхронную функцию, выполняющую одну из таких операций
blocking_, рассмотрите возможность обернуть этот вызов вspawn_blocking()(илиblock_in_place()).
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
#[tokio::main]
async fn main() {
let rwlock = Arc::new(RwLock::new(1));
let mut write_lock = rwlock.write().await;
let blocking_task = tokio::task::spawn_blocking({
let rwlock = Arc::clone(&rwlock);
move || {
// This shall block until the `write_lock` is released.
let read_lock = rwlock.blocking_read();
assert_eq!(*read_lock, 0);
}
});
*write_lock -= 1;
drop(write_lock); // release the lock.
// Await the completion of the blocking task.
blocking_task.await.unwrap();
// Assert uncontended.
assert!(rwlock.try_write().is_ok());
}pub async fn read_owned(self: Arc<Self>) -> OwnedRwLockReadGuard<T>
Блокирует этот RwLock для совместного чтения, приостанавливая текущую задачу до получения блокировки.
Вызывающая задача будет приостановлена, пока блокировку удерживают писатели. Когда задача возобновится, внутри блокировки могут находиться другие читатели.
Этот метод идентичен RwLock::read, за исключением того, что возвращаемый guard ссылается на RwLock через Arc, а не посредством заимствования. Поэтому для вызова этого метода RwLock необходимо обернуть в Arc, а guard будет жить столько же, сколько 'static, поскольку он сохраняет RwLock живым, удерживая Arc.
Обратите внимание: согласно политике приоритетов RwLock, блокировки на чтение не выдаются, пока не будут обработаны ранее запрошенные блокировки на запись, чтобы предотвратить голодание. Поэтому может возникнуть взаимная блокировка, если текущая задача удерживает блокировку на чтение, затем запрашивает блокировку на запись, а после этого запрашивает ещё одну блокировку на чтение.
Возвращает RAII-guard, который при удалении освобождает доступ на чтение к RwLock.
Безопасность при отмене
Этот метод использует очередь, чтобы справедливо распределять блокировки в порядке их запроса. Отмена вызова read_owned приведёт к потере места в очереди.
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let n = lock.read_owned().await;
assert_eq!(*n, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let r = c_lock.read_owned().await;
assert_eq!(*r, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard after the spawned task finishes.
drop(n);
}pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError>
Пытается получить совместный доступ для чтения к этому RwLock.
Если доступ не удалось получить немедленно, возвращает TryLockError. В противном случае возвращается RAII-guard, который освободит доступ для чтения при удалении.
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let v = lock.try_read().unwrap();
assert_eq!(*v, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let n = c_lock.read().await;
assert_eq!(*n, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard when spawned task finishes.
drop(v);pub fn try_read_owned( self: Arc<Self>, ) -> Result<OwnedRwLockReadGuard<T>, TryLockError>
Пытается получить совместный доступ для чтения к этому RwLock.
Если доступ не удалось получить немедленно, возвращает TryLockError. В противном случае возвращается RAII-guard, который освободит доступ для чтения при удалении.
Этот метод идентичен RwLock::try_read, за исключением того, что возвращаемый guard ссылается на RwLock через Arc, а не посредством заимствования. Поэтому для вызова этого метода RwLock необходимо обернуть в Arc, а guard будет жить столько же, сколько 'static, поскольку он сохраняет RwLock живым, удерживая Arc.
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let v = lock.try_read_owned().unwrap();
assert_eq!(*v, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let n = c_lock.read_owned().await;
assert_eq!(*n, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard when spawned task finishes.
drop(v);pub async fn write(&self) -> RwLockWriteGuard<'_, T>
Блокирует этот RwLock для исключительной записи, приостанавливая текущую задачу до получения блокировки.
Вызывающая задача будет приостановлена, пока другие писатели или читатели имеют доступ к блокировке.
Возвращает RAII-guard, который при удалении освобождает доступ для записи к этому RwLock.
Безопасность при отмене
Этот метод использует очередь, чтобы справедливо распределять блокировки в порядке их запроса. Отмена вызова write приведёт к потере места в очереди.
Примеры
use tokio::sync::RwLock;
let lock = RwLock::new(1);
let mut n = lock.write().await;
*n = 2;pub fn blocking_write(&self) -> RwLockWriteGuard<'_, T>
Блокирует этот RwLock в синхронном режиме для исключительной записи.
Этот метод предназначен для случаев, когда требуется использовать этот rwlock как в асинхронном, так и в синхронном коде.
Возвращает RAII-guard, который при удалении освобождает доступ для записи к этому RwLock.
Паника
Эта функция вызывает панику, если её вызвать в контексте асинхронного выполнения.
- Если вы находитесь в контексте асинхронного выполнения и вам нужно вызвать какую-либо (синхронную) функцию, выполняющую одну из этих операций с
blocking_, рассмотрите возможность обернуть этот вызов вspawn_blocking()(илиblock_in_place()).
Примеры
use std::sync::Arc;
use tokio::{sync::RwLock};
#[tokio::main]
async fn main() {
let rwlock = Arc::new(RwLock::new(1));
let read_lock = rwlock.read().await;
let blocking_task = tokio::task::spawn_blocking({
let rwlock = Arc::clone(&rwlock);
move || {
// This shall block until the `read_lock` is released.
let mut write_lock = rwlock.blocking_write();
*write_lock = 2;
}
});
assert_eq!(*read_lock, 1);
// Release the last outstanding read lock.
drop(read_lock);
// Await the completion of the blocking task.
blocking_task.await.unwrap();
// Assert uncontended.
let read_lock = rwlock.try_read().unwrap();
assert_eq!(*read_lock, 2);
}pub async fn write_owned(self: Arc<Self>) -> OwnedRwLockWriteGuard<T>
Блокирует этот RwLock для эксклюзивного доступа на запись, приостанавливая текущую задачу до получения блокировки.
Вызывающая задача будет приостановлена, пока другие задачи записи или чтения имеют доступ к блокировке.
Этот метод идентичен RwLock::write, за исключением того, что возвращаемый охранник ссылается на RwLock через Arc, а не заимствуя его. Поэтому для вызова этого метода RwLock необходимо обернуть в Arc, а охранник будет жить в течение всего времени жизни 'static, поскольку он удерживает RwLock активным, владея Arc.
Возвращает охранник RAII, который при удалении освободит доступ на запись к этому RwLock.
Безопасность при отмене
Этот метод использует очередь для справедливого распределения блокировок в порядке поступления запросов. Отмена вызова write_owned приведёт к потере вашего места в очереди.
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let mut n = lock.write_owned().await;
*n = 2;
}pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError>
Пытается получить эксклюзивный доступ на запись к этому RwLock.
Если получить доступ немедленно не удалось, возвращает TryLockError. В противном случае возвращается охранник RAII, который при удалении освободит доступ на запись.
Примеры
use tokio::sync::RwLock;
let rw = RwLock::new(1);
let v = rw.read().await;
assert_eq!(*v, 1);
assert!(rw.try_write().is_err());pub fn try_write_owned( self: Arc<Self>, ) -> Result<OwnedRwLockWriteGuard<T>, TryLockError>
Пытается получить эксклюзивный доступ на запись к этому RwLock.
Если получить доступ немедленно не удалось, возвращает TryLockError. В противном случае возвращается охранник RAII, который при удалении освободит доступ на запись.
Этот метод идентичен RwLock::try_write, за исключением того, что возвращаемый охранник ссылается на RwLock через Arc, а не заимствуя его. Поэтому для вызова этого метода RwLock необходимо обернуть в Arc, а охранник будет жить в течение всего времени жизни 'static, поскольку он удерживает RwLock активным, владея Arc.
Примеры
use std::sync::Arc;
use tokio::sync::RwLock;
let rw = Arc::new(RwLock::new(1));
let v = Arc::clone(&rw).read_owned().await;
assert_eq!(*v, 1);
assert!(rw.try_write_owned().is_err());pub fn get_mut(&mut self) -> &mut T
Возвращает изменяемую ссылку на базовые данные.
Поскольку этот вызов изменяемо заимствует RwLock, фактическая блокировка не требуется — изменяемое заимствование статически гарантирует, что блокировок нет.
Примеры
use tokio::sync::RwLock;
fn main() {
let mut lock = RwLock::new(1);
let n = lock.get_mut();
*n = 2;
}pub fn into_inner(self) -> Twhere T: Sized,
Потребляет блокировку и возвращает базовые данные.
Реализации трейтов
impl<T> From<T> for RwLock<T>
fn from(s: T) -> Self
impl<T> Send for RwLock<T>
impl<T> Sync for RwLock<T>
Реализации автоматических трейтов
impl<T> !Freeze for RwLock<T>
impl<T> !RefUnwindSafe for RwLock<T>
impl<T> !UnwindSafe for RwLock<T>
impl<T> Unpin for RwLock<T>
impl<T> UnsafeUnpin for RwLock<T>where T: UnsafeUnpin + ?Sized,
Общие реализации
impl<T> BorrowMut<T> for Twhere T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
impl<T> Instrument for T
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
impl<T> WithSubscriber for T
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ
Subscriber к этому типу, возвращая обёртку WithDispatch. Подробнее
MIT License
Copyright © Tokio Contributors
https://docs.rs/tokio/1.53.1/tokio/sync/struct.RwLock.html