Структура RwLock

Описание: Блокировка "читатель-писатель" (reader-writer lock)

Этот тип блокировки позволяет нескольким читателям или не более чем одному писателю в любой момент времени. Часть записи этой блокировки обычно позволяет изменять базовые данные (эксклюзивный доступ), а часть чтения обычно позволяет только чтение (разделяемый доступ).

В отличие от Mutex, который не различает читателей и писателей, блокируя все потоки, ожидающие освобождения блокировки, RwLock позволяет любому количеству читателей получить блокировку, пока писатель не удерживает её.

Политика приоритетов блокировки зависит от реализации базовой операционной системы, и этот тип не гарантирует использование какой-либо конкретной политики.

Стабильность: 1.0.0

Отравление (Poisoning)

RwLock, как и Mutex, обычно становится "отравленным" при панике. Однако RwLock может быть отравлен только если паника происходит во время эксклюзивной блокировки (режим записи). Если паника происходит в любом читателе, блокировка не будет отравлена.

Примеры

#![allow(unused)]
fn main() {
use std::sync::RwLock;

let lock = RwLock::new(5);

// множество блокировок чтения может удерживаться одновременно
{
    let r1 = lock.read().unwrap();
    let r2 = lock.read().unwrap();
    assert_eq!(*r1, 5);
    assert_eq!(*r2, 5);
} // блокировки чтения снимаются здесь

// только одна блокировка записи может удерживаться
{
    let mut w = lock.write().unwrap();
    *w += 1;
    assert_eq!(*w, 6);
} // блокировка записи снимается здесь
}

Методы

new (стабильность: 1.0.0, const с 1.63.0)

#![allow(unused)]
fn main() {
pub const fn new(t: T) -> RwLock<T>
}

Создает новый экземпляр RwLock<T> в разблокированном состоянии.

get_cloned (экспериментальный)

#![allow(unused)]
fn main() {
pub fn get_cloned(&self) -> Result<T, PoisonError<()>>
}

Возвращает содержащееся значение путем его клонирования.

Ошибки: Возвращает ошибку, если RwLock отравлен.

set (экспериментальный)

#![allow(unused)]
fn main() {
pub fn set(&self, value: T) -> Result<(), PoisonError<T>>
}

Устанавливает содержащееся значение.

Ошибки: Возвращает ошибку, содержащую предоставленное value, если RwLock отравлен.

replace (экспериментальный)

#![allow(unused)]
fn main() {
pub fn replace(&self, value: T) -> LockResult<T>
}

Заменяет содержащееся значение на value и возвращает старое значение.

Ошибки: Возвращает ошибку, содержащую предоставленное value, если RwLock отравлен.

impl<T: ?Sized> RwLock<T>

read (стабильность: 1.0.0)

#![allow(unused)]
fn main() {
pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>>
}

Блокирует этот RwLock с разделяемым доступом на чтение, блокируя текущий поток до получения доступа.

Возвращает RAII-гард, который снимет разделяемый доступ при удалении.

Ошибки: Возвращает ошибку, если RwLock отравлен.

#![allow(unused)]
fn main() {
use std::sync::{Arc, RwLock};
use std::thread;

let lock = Arc::new(RwLock::new(1));
let c_lock = Arc::clone(&lock);

let n = lock.read().unwrap();
assert_eq!(*n, 1);

thread::spawn(move || {
    let r = c_lock.read();
    assert!(r.is_ok());
}).join().unwrap();
}

try_read (стабильность: 1.0.0)

#![allow(unused)]
fn main() {
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>>
}

Пытается получить этот RwLock с разделяемым доступом на чтение.

Не блокирует поток. Возвращает WouldBlock, если блокировка уже захвачена эксклюзивно.

#![allow(unused)]
fn main() {
use std::sync::RwLock;

let lock = RwLock::new(1);

match lock.try_read() {
    Ok(n) => assert_eq!(*n, 1),
    Err(_) => unreachable!(),
};
}

write (стабильность: 1.0.0)

#![allow(unused)]
fn main() {
pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>>
}

Блокирует этот RwLock с эксклюзивным доступом на запись, блокируя текущий поток до получения доступа.

Возвращает RAII-гард, который снимет доступ на запись при удалении.

Ошибки: Возвращает ошибку, если RwLock отравлен.

#![allow(unused)]
fn main() {
use std::sync::RwLock;

let lock = RwLock::new(1);

let mut n = lock.write().unwrap();
*n = 2;

assert!(lock.try_read().is_err());
}

try_write (стабильность: 1.0.0)

#![allow(unused)]
fn main() {
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>>
}

Пытается заблокировать этот RwLock с эксклюзивным доступом на запись.

Не блокирует поток. Возвращает WouldBlock, если блокировка уже захвачена.

#![allow(unused)]
fn main() {
use std::sync::RwLock;

let lock = RwLock::new(1);

let n = lock.read().unwrap();
assert_eq!(*n, 1);

assert!(lock.try_write().is_err());
}

is_poisoned (стабильность: 1.2.0)

#![allow(unused)]
fn main() {
pub fn is_poisoned(&self) -> bool
}

Определяет, отравлена ли блокировка.

Не следует доверять значению false для корректности программы без дополнительной синхронизации.

#![allow(unused)]
fn main() {
use std::sync::{Arc, RwLock};
use std::thread;

let lock = Arc::new(RwLock::new(0));
let c_lock = Arc::clone(&lock);

let _ = thread::spawn(move || {
    let _lock = c_lock.write().unwrap();
    panic!(); // the lock gets poisoned
}).join();
assert_eq!(lock.is_poisoned(), true);
}

clear_poison (стабильность: 1.77.0)

#![allow(unused)]
fn main() {
pub fn clear_poison(&self)
}

Очищает отравленное состояние блокировки.

Позволяет восстановиться из отравленного состояния и отметить это.

#![allow(unused)]
fn main() {
use std::sync::{Arc, RwLock};
use std::thread;

let lock = Arc::new(RwLock::new(0));
let c_lock = Arc::clone(&lock);

let _ = thread::spawn(move || {
    let _lock = c_lock.write().unwrap();
    panic!(); // the lock gets poisoned
}).join();

assert_eq!(lock.is_poisoned(), true);
let guard = lock.write().unwrap_or_else(|mut e| {
    **e.get_mut() = 1;
    lock.clear_poison();
    e.into_inner()
});
assert_eq!(lock.is_poisoned(), false);
assert_eq!(*guard, 1);
}

into_inner (стабильность: 1.6.0)

#![allow(unused)]
fn main() {
pub fn into_inner(self) -> LockResult<T>
}

Потребляет этот RwLock, возвращая базовые данные.

Ошибки: Возвращает ошибку, содержащую базовые данные, если RwLock отравлен.

#![allow(unused)]
fn main() {
use std::sync::RwLock;

let lock = RwLock::new(String::new());
{
    let mut s = lock.write().unwrap();
    *s = "modified".to_owned();
}
assert_eq!(lock.into_inner().unwrap(), "modified");
}

get_mut (стабильность: 1.6.0)

#![allow(unused)]
fn main() {
pub fn get_mut(&mut self) -> LockResult<&mut T>
}

Возвращает изменяемую ссылку на базовые данные.

Не требует фактической блокировки, так как заимствует RwLock изменяемо.

#![allow(unused)]
fn main() {
use std::sync::RwLock;

let mut lock = RwLock::new(0);
*lock.get_mut().unwrap() = 10;
assert_eq!(*lock.read().unwrap(), 10);
}

data_ptr (экспериментальный)

#![allow(unused)]
fn main() {
pub const fn data_ptr(&self) -> *mut T
}

Возвращает сырой указатель на базовые данные.

Пользователь несет ответственность за правильную синхронизацию операций чтения/записи.

Реализации трейтов

Debug (стабильность: 1.0.0)

Реализует форматирование для отладки (где T: Debug).

Default (стабильность: 1.10.0)

Создает новый RwLock<T> со значением по умолчанию для T (где T: Default).

From<T> (стабильность: 1.24.0)

Создает новый экземпляр RwLock<T> в разблокированном состоянии. Эквивалентно RwLock::new.

Безопасность потоков

  • Send (где T: Send)
  • Sync (где T: Send + Sync)
  • RefUnwindSafe
  • UnwindSafe

Автоматические реализации трейтов

  • !Freeze
  • Unpin (где T: Unpin)

Стандартные реализации

  • Any
  • Borrow<T>
  • BorrowMut<T>
  • From<!>
  • From<T>
  • Into<U>
  • TryFrom<U>
  • TryInto<U>