Rust从入门到实战系列一百九十一:共享状态并发

本文探讨了在并发编程中,尽管消息传递是一种流行的方法,但Rust通过其类型系统和所有权规则支持的共享内存机制(如互斥器Mutex)。作者以单线程和互斥器为例,展示了如何在Rust中管理和避免并发问题,以及为何消息传递爱好者不直接使用共享内存的复杂性。
摘要由CSDN通过智能技术生成

ch16-03-shared-state.md commit 75b9d4a8dccc245e0343eb1480aa86f169043ea5
虽然消息传递是一个很好的处理并发的方式,但并不是唯一一个。再一次思考一下 Go 编程语言文档中
口号的这一部分:” 不要通过共享内存来通讯”(”do not communicate by sharing memory.”):
What would communicating by sharing memory look like? In addition, why would message
passing enthusiasts not use it and do the opposite instead?
通过共享内存通讯看起来如何?除此之外,为何消息传递的拥护者并不使用它并反其道而行之呢?
在某种程度上,任何编程语言中的通道都类似于单所有权,因为一旦将一个值传送到通道中,将无法再
使用这个值。共享内存类似于多所有权:多个线程可以同时访问相同的内存位置。第十五章介绍了智能
指针如何使得多所有权成为可能,然而这会增加额外的复杂性,因为需要以某种方式管理这些不同的所
有者。Rust 的类型系统和所有权规则极大的协助了正确地管理这些所有权。作为一个例子,让我们看看
互斥器,一个更为常见的共享内存并发原语。
互斥器一次只允许一个线程访问数据
互斥器(mutex)是 mutual exclusion 的缩写,也就是说,任意时刻,其只允许一个线程访问某些数据。
为了访问互斥器中的数据,线程首先需要通过获取互斥器的 锁(lock)来表明其希望访问数据。锁是一
个作为互斥器一部分的数据结构,它记录谁有数据的排他访问权。因此,我们描述互斥器为通过锁系统
保护(guarding)其数据。
互斥器以难以使用著称,因为你不得不记住:

  1. 在使用数据之前尝试获取锁。
  2. 处理完被互斥器所保护的数据之后,必须解锁数据,这样其他线程才能够获取锁。
    作为一个现实中互斥器的例子,想象一下在某个会议的一次小组座谈会中,只有一个麦克风。如果一位
    成员要发言,他必须请求或表示希望使用麦克风。一旦得到了麦克风,他可以畅所欲言,然后将麦克风
    交给下一位希望讲话的成员。如果一位成员结束发言后忘记将麦克风交还,其他人将无法发言。如果对
    共享麦克风的管理出现了问题,座谈会将无法如期进行!
    正确的管理互斥器异常复杂,这也是许多人之所以热衷于通道的原因。然而,在 Rust 中,得益于类型系
    统和所有权,我们不会在锁和解锁上出错。
    Mutex 的 API
    作为展示如何使用互斥器的例子,让我们从在单线程上下文使用互斥器开始,如示例 16-12 所示:
    文件名: src∕main.rs
    use std::sync::Mutex;
    fn main() {
    let m = Mutex::new(5);
    {
    let mut num = m.lock().unwrap();
    *num = 6;
    }
    println!(“m = {:?}”, m);
    }
    示例 16-12: 出于简单的考虑,在一个单线程上下文中探索 Mutex 的 API
    像很多类型一样,我们使用关联函数 new 来创建一个 Mutex。使用 lock 方法获取锁,以访问互斥
    器中的数据。这个调用会阻塞当前线程,直到我们拥有锁为止。
    如果另一个线程拥有锁,并且那个线程 panic 了,则 lock 调用会失败。在这种情况下,没人能够再获取
    锁,所以这里选择 unwrap 并在遇到这种情况时使线程 panic。
    一旦获取了锁,就可以将返回值(在这里是num)视为一个其内部数据的可变引用了。类型系统确保了
    我们在使用 m 中的值之前获取锁:Mutex 并不是一个 i32,所以 必须获取锁才能使用这个 i32 值。
    我们是不会忘记这么做的,因为反之类型系统不允许访问内部的 i32 值。
    正如你所怀疑的,Mutex 是一个智能指针。更准确的说,lock 调用 返回一个叫做 MutexGuard 的智
    能指针。这个智能指针实现了 Deref 来指向其内部数据;其也提供了一个 Drop 实现当 MutexGuard 离
    开作用域时自动释放锁,这正发生于示例 16-12 内部作用域的结尾。为此,我们不会冒忘记释放锁并阻
    塞互斥器为其它线程所用的风险,因为锁的释放是自动发生的。
    丢弃了锁之后,可以打印出互斥器的值,并发现能够将其内部的 i32 改为 6。
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值