54_共享状态的并发

1. 概述

"不要用共享的内存来通信,要用通信来共享内存"。实际上,在上节中我们就是使用通信的方式来实现并发的,在本节我们要使用共享内存的方式来实现并发。

rust支持通过共享状态来实现并发。channel类似于单所有权,一旦将值的所有权转移至channel,就无法使用它了。而共享内存的并发方式类似多所有权,多个线程可以同时访问一块内存。

在rust里使用Mutex来每次只允许一个线程来访问数据,是mutual exclusion(互斥锁)的简写。在同一时刻,Mutex只允许一个线程来访问某些数据。想要访问数据,线程必须首先获取互斥锁(lock)。lock数据结构是mutex的一部分,它能跟踪谁对数据拥有独占访问权。mutex通常被描述为:通过锁定系统来保护它所持有的数据。

2. Mutext的两条规则

  • 在使用数据之前,必须尝试获取锁(lock)。
  • 使用完mutex所保护的数据,必须对数据进行解锁,以便其他线程可以获取锁。

3. Mutex的API

通过Mutex::new(数据)来创建Mutex<T>Mutex<T>是一个智能指针,在访问数据之前,通过lock方法来获取锁。这个方法会阻塞当前线程的执行,返回的是MutexGuard(智能指针,实现了Deref和Drop),但lock方法可能会失败。

如下示例代码:

rust 复制代码
use std::sync::Mutex;

fn main() {
    let m = Mutex::new(5);

    {
        // 获取数据的可变引用
        let mut num = m.lock().unwrap();
        // 变更数据
        *num = 6;
    }
    // 由于MutexGuard实现了 Drop trait,当作用域走完,m被自动解锁

    println("m = {"?"}", m);
}

4. 多线程共享Mutex

在rust里使用Arc<T>来进行原子引用计数,Arc<T>Rc<T>类似,它可以用于并发场景。A是atomic的简称,即原子的。这时候你可以有一个问题,为什么所有的基础类型都不是原子的,为什么标准库类型不默认使用Arc<T>?因为需要付出性能代价。Arc<T>Rc<T>的API是相同的。

如下示例代码:

rust 复制代码
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // 创建一个数据
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    // 创建10个线程去修改数据,再把返回的10个JoinHandle放到handles中
    for _ in 0..10 {
        let counter = Arc::clone(&counter);

        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });

        handles.push(handle);
    }

    // 等待所有线程运行完成
    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

最终运行结果为10

5. RefCell/Rc和Mutex/Arc

Mutext<T>提供了内部可变性,和Cell家族一样。我们可以使用RefCell<T>改变Rc<T>里面的内容,同样可以使用Mutex<T>来改变Arc<T>里面的内容。

但要注意的是,使用Rc<T>可能会造成循环引用,造成内存泄漏的风险;而使用Mutex<T>也有死锁的风险。所谓的死锁,就是当某个操作需要同时锁住两个资源,两个线程分别持有其中一个锁,并相互请求另外一个锁的时候,这两个线程就会陷入无穷无尽的等待。

相关推荐
华玥作者3 小时前
[特殊字符] VitePress 对接 Algolia AI 问答(DocSearch + AI Search)完整实战(下)
前端·人工智能·ai
Mr Xu_3 小时前
告别冗长 switch-case:Vue 项目中基于映射表的优雅路由数据匹配方案
前端·javascript·vue.js
前端摸鱼匠3 小时前
Vue 3 的toRefs保持响应性:讲解toRefs在解构响应式对象时的作用
前端·javascript·vue.js·前端框架·ecmascript
lang201509283 小时前
JSR-340 :高性能Web开发新标准
java·前端·servlet
好家伙VCC4 小时前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
未来之窗软件服务5 小时前
未来之窗昭和仙君(六十五)Vue与跨地区多部门开发—东方仙盟练气
前端·javascript·vue.js·仙盟创梦ide·东方仙盟·昭和仙君
嘿起屁儿整5 小时前
面试点(网络层面)
前端·网络
VT.馒头5 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
phltxy6 小时前
Vue 核心特性实战指南:指令、样式绑定、计算属性与侦听器
前端·javascript·vue.js
Byron07077 小时前
Vue 中使用 Tiptap 富文本编辑器的完整指南
前端·javascript·vue.js