(25条消息) 【Rust每周一知】Rust中的读写锁RwLock

本文简单介绍 Rust 中的读写锁RwLock,内容概览如下:

  • 经典问题

    • 读者-作家问题

  • 基本概念

    • 临界区 Critical p

    • 互斥量 Mutex

    • 信号量 Semaphore

    • 读写锁 RWLock

  • Rust中的RwLock实现

    • std::sync::RwLock

    • parking_lot::RwLock

经典问题

在计算机科学中,有一些经典的同步问题,读者-作家问题就是其中一个,该问题涉及多个并发线程试图同时访问同一共享资源的情况。

读者-作家问题:我们拥有一种资源(例如,数据库),可以由不修改资源的读者和可以修改资源的作家访问。当作家修改资源时,其他任何人(读者或作家)都无法同时访问它,因为另一位作家可能破坏资源,而另一位读者可能读取部分修改的值,因此可能出现不一致。

基本概念

为了准确理解问题,我们先介绍一些基本概念。

临界区 Critical p,在并发编程中,对共享资源的并发访问可能导致意外或错误的行为,因此需要以某种方式保护访问共享资源的那部分程序。这部分受保护的代码片段称为临界区。

互斥量 Mutex,在多线程并发编程时,为了确保一次仅一个线程可以访问共享资源,引入了Mutex的概念,它是 Mutual Exclusion 的缩写,通常翻译为互斥量或互斥锁。

信号量 Semaphore,同样的,为了控制并发系统中多个线程对共享资源的访问,引入了Semaphore的概念,通常翻译为信号量。

读写锁 RWLock,在计算机科学中,读写锁是解决读者-作家问题的同步原语之一。读写锁允许读操作共享访问,而写操作则需要互斥访问。通常构造在互斥量和条件变量之上,或者构造在信号量之上。

Rust中的读写锁

自读者-作家问题提出以来,人们对它进行了广泛的研究,读写锁是解决读者-作家问题的方案之一,按照读写锁的锁定优先级策略分为以下三种:

  • 赋予读者优先权:当前至少有一个读者正在访问资源时,也应允许新读者访问它。如果有作家在等待修改资源并且新的读者一直到来,这可能会导致作家饿死,因为只要有至少一个读者,就永远不会授予作家访问权限。

  • 赋予作家优先权:在这里,读者可能会饿死。

  • 不给予任何优先权:所有读者和作家都将按到达顺序被授予对资源的访问权限。如果在读者访问资源时作家到达,它将等待这些读者释放资源,然后对其进行修改。同时抵达的新读者将不得不等待。

标准库中的RwLock

  • 允许在任何时间点具有多个读者或最多一个作家。也就是说,RwLock允许任何数量的读者获取锁,只要作家未持有该锁即可。

  • 相比之下,互斥锁不会区分获取锁的种类,因此会阻塞等待可用锁的所有线程。

  • 锁定策略取决于操作系统的实现,也就是说它不能保证将使用任何特定的锁定策略

    • Windows和macOS,读者和作家公平排队

    • Linux,读者优先,作家会出现饥饿现象

同时,第三方库parking_lot中也实现了RwLock,它与标准库的RwLock的主要区别是:

  • 其锁定策略是任务公平(task-fair),而不是未指定的平台默认值,避免出现读者作家饥饿现象。

  • 仅需要1个字的空间,而标准库由于平台限制而将RwLock装箱。

  • 该锁在出现紧急情况时通常会被释放,无“中毒”(poisoning)现象。

基本的使用,示例如下:

#[macro_use]extern crate lazy_static;use std::thread;use std::sync::RwLock;//use parking_lot::RwLock;lazy_static! {pub static ref INC: RwLock<i32> = RwLock::new(0);}fn main() {let thread1 = thread::spawn(|| {for i in 1..10 {let mut w = INC.write().unwrap();//let mut w = INC.write();*w = *w + 1;}});let thread2 = thread::spawn(|| {for i in 1..10 {let mut w = INC.write().unwrap();//let mut w = INC.write();*w = *w + 1;}});thread1.join().unwrap();thread2.join().unwrap();let r = INC.read().unwrap();//let r = INC.read();println!("{}", *r); // 输出 18}

一般项目中会有对全局配置文件的操作,示例如下:

#[macro_use]extern crate lazy_static;use std::sync::RwLock;#[derive(Debug, Clone, Copy)]pub struct MyConfig {pub debug: bool,pub info: &'static str,}lazy_static! {pub static ref CONFIG: RwLock<MyConfig> = RwLock::new(MyConfig { debug: false, info: "Some info" });}impl MyConfig {pub fn init(custom_debug: Option<bool>, custom_info: Option<&'static str>) -> Result<(), i32> {let mut w = CONFIG.write().unwrap();match (custom_debug , custom_info) {(Some(debug_value), Some(custom_info)) => *w = MyConfig { debug: debug_value, info: custom_info},_ => (),};Ok(())}pub fn global_config() -> MyConfig {let m = CONFIG.read().unwrap();// 返回配置的拷贝*m}}fn main() {let a = MyConfig::global_config();dbg!(a);MyConfig::init(Some(true), Some("Updated"));let a = MyConfig::global_config();dbg!(a);}

输出:

[src/main.rs:39] a = MyConfig {debug: false,info: "Some info",}[src/main.rs:45] a = MyConfig {debug: true,info: "Updated",}

希望对大家理解RwLock有帮助,欢迎交流,self-fulfil。

(0)

相关推荐

  • 面向非C/C 开发者的Rust并发

    马克西姆-扎韦尔辛斯基 12分钟阅读 最低限度. 大多数来到Rust的人都有C/C++的背景,这使得他们可以轻松地过渡到Rust的并行性,因为它是如此相似.然而,对于许多来自其他语言的人来说,这是一个 ...

  • python测试开发django-97.设置DEBUG = False后静态资源不显示问题

    前言 设置DEBUG = False后,访问web页面,发现静态资源不显示,无法加载到静态资源. 问题描述 django 项目部署正式环境,设置DEBUG = False后,访问admin后台页面,页 ...

  • 小小的坚持

    一个多月前,碰巧,遇见一位网红作家的新书签售会. 该作家,每日微信公众号发文,圈粉无数.新书签售会现场也来了两百多人. 在作家和读者畅聊环节,有位读者提出了一个颇为犀利的问题:"听说,文章不 ...

  • python测试开发django-82.线上部署设置DEBUG=FALSE

    前言 django项目线上部署到云服务器,setting里面设置DEBUG=FALSE后,访问网站静态资源没显示相关问题解决. 准备工作: 1.一台服务器,如阿里云,腾讯云, 或者自己整个虚拟机 2. ...

  • 我对打赏的看法

    打赏 接受打赏是因为作家的作品可以产生价值,得到报赏. 打赏是读者感谢作家写出了那篇文章. 读者享受打赏,那是付出的快乐. 打赏是一种自愿的,善意的流露. 不打赏的人隐藏自己的情感,有时并不是出于自私 ...

  • (25条消息) rust 声明宏中可以捕获的类型列表

    item, 代表语言项,就是组成一个 Rust 包的基本单位,比如模块.声明.函数定义 .类型定义.结构体定义. imp!实现等. block ,代表代码块,由花括号限定的代码. stmt,代表语句 ...

  • (25条消息) Rust 中的属性

    属性是什么 属性(Attribute)是一种通用的自由格式的元数据,Rust 中的属性以ECMA-335中的为模型,其语法则来自ECMA-334(C#). 属性的用途 属性只能应用于 Rust 中的项 ...

  • (25条消息) Rust: 属性(attribute)的含义及文档大全

    Rust中满地都是属性,对于这些,我们是需要有所了解,否则会感觉 到晕: #[lang="copy"] :表示Rust语言本身使用 #[lang ="drop" ...

  • (25条消息) rust多个属性宏叠加

    Rust的属性标记,不敢说这是创新,但是很有趣,很有用. 基本格式类似: #[xxx] 它有十三个种类,它们是... 我猜你已经准备头痛了.我们以一个简单有用的例子来说明吧. 它就是牛B闪闪 test ...

  • (25条消息) vue中 关于$emit的用法

    (25条消息) vue中 关于$emit的用法

  • (25条消息) 在Vue中使用async函数

    在Vue中使用async函数 async/await语法 在生命周期钩子上使用async函数 在methods中使用async函数 源代码 async/await语法 在ES7标准中新增了async和 ...

  • 【Rust每周一知】 Attribute 属性

    属性是作用在 Rust 语言元素上的元数据. Rust 中的属性数量非常多.而且具有可扩展性(可自定义属性).Rust 的属性语法遵从 C# 定义并标准化了的属性规范ECMA-334. Rust 代码 ...

  • (59条消息) 终于讲清楚了nodejs中exports和module.exports的区别

    module.exports 对象是由模块系统创建的.在我们自己写模块的时候,需要在模块最后写好模块接口,声明这个模块对外暴露什么内容,module.exports 提供了暴露接口的方法. 1.返回一 ...

  • (1条消息) Android Studio在Gradle中调用cmd脚本

    Gradle中调用cmd 需要在Gradle编译时,调用某些脚本进行文件操作,比如:头文件更新,或者动态链接库文件的更新等,需要借助脚本文件,并且不需要手动运行,那么如何使用Gradle呢? 如下代码 ...