rust学习十六.3、并发-线程之间共享数据

news/2025/1/12 12:21:57/文章来源:https://www.cnblogs.com/lzfhope/p/18664452

线程之间共享数据,即go中部分人所憎恶的方式!

然而,这个方式并非没有其优点,否则操作系统也不提供这种实现方式。

 

闲言少序,上正文!

一、概述

 * 1.当我们大谈基于信道通信时,应该指的是应用级别。如果是操作系统,应该还是会有多种措施的,否则rust的源头在哪里来着。
 * 2.rust共享内存,主要借助于Arc指针实现。所谓Arc,是Atomically Reference Counted的缩写,即原子引用计数。 它和Rc的主要
 *   区别在于,Arc允许多线程同时访问,而Rc不允许。
 * 3.此外还需要借助于Mutex(mutual exclusion 互相排斥之意),即互斥锁,来保证同一时刻只有一个线程可以访问共享资源。
 * 4.Mutex的主要方法有lock(),lock用于获取锁,如果成功返回一个MutexGuard智能指针。获取锁的时候,会阻塞线程
 * 5.MutexGuard智能指针实现了Deref和Drop,因此可以被当作原始数据的引用,同时Drop确保了当MutexGuard离开作用域时,锁会被释放。
 * 6.Mutex 是一个类似RefCell的智能指针,都提供了内部可变性
 * 7.Mutex<T> 也有造成 死锁(deadlock)的风险:当某个操作需要锁住两个资源,而两个线程分别持有两个资源的其中一个锁时,它们会永远相互等待
 * 8.对于简单的数值运算,标准库中 std::sync::atomic 模块 提供了比 Mutex<T> 更简单的类型。针对基本类型,这些类型提供了安全、并发、原子的操作
 *   例如 AtomicI32
 
Mutex的结构代码
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Mutex")]
pub struct Mutex<T: ?Sized> {inner: sys::Mutex,poison: poison::Flag,data: UnsafeCell<T>,
}

 

这个sys::Mutex是一个原子:

pub struct Mutex {futex: Atomic,
}
 用于持有锁position(位置标记/占有标记)是一个原子布尔,用于表示是否被占有data就是原始的数据了。
 Mutex最常用的方法lock用于获得锁,并返回如下:
 #[stable(feature = "rust1", since = "1.0.0")]pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {unsafe {self.inner.lock();MutexGuard::new(self)}}
 这段代码的大概意思:调用操作系统的内部锁,返回一个新的MutexGuard。完整的结果就是包含一个锁和一个结果 

二、示例-来自于书本的

use std::sync::{Arc, Mutex};
use std::thread;
fn main() {let counter = Arc::new(Mutex::new(0));let mut handles = vec![];for _ in 0..10 {let c = Arc::clone(&counter);let handle = thread::spawn(move || {let mut num = c.lock().unwrap();*num += 1;println!("线程{:?}正在执行,得到{}", thread::current().id(),*num);});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Result: {}", *counter.lock().unwrap());
}

借用Arc指针(多线程使用的,可以共享数据)和Mutex锁实现简单的数字自增游戏! 很像餐桌上大伙共享一个公勺,有了公勺你要干什么都可以,但一个时刻只有一把公勺!

 

三、示例-特意构建的死锁

根据书本的要求,我特意构建一个死锁的代码。

发生死锁的最主要原因是互相等待对方持有的资源,好比劫匪持有人质,警察要人质,常常会陷入死循环!直到一方崩溃

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {let 人质 = Arc::new(Mutex::new(5));    let 自由 = Arc::new(Mutex::new(10));let h0=Arc::clone(&人质);let w0=Arc::clone(&自由);let 劫匪=thread::spawn(move || {      //线程0先获得人质资源,然后等待一段时间再获得自由资源。let mut _heigth = h0.lock().unwrap();        thread::sleep(Duration::from_millis(10));println!("我已经持有人质,快点让路!");let mut _自由 = w0.lock().unwrap();let area = (*_heigth) * (*_自由);println!("线程{:?}正在执行,得到{}", thread::current().id(), area);});let h1=Arc::clone(&人质);let w1=Arc::clone(&自由);let 警察=thread::spawn(move || {//线程1先获得的自由资源,然后等待一段时间再获得人质资源。let mut _自由 = w1.lock().unwrap();thread::sleep(Duration::from_millis(10));println!("赶紧放了人质,否则爆你狗头!");let mut _heigth = h1.lock().unwrap();        let area = (*_heigth) * (*_自由);println!("线程{:?}正在执行,得到{}", thread::current().id(), area);});劫匪.join().unwrap();警察.join().unwrap();println!("众人在围观....");let  _heigth = 人质.lock().unwrap();let  _自由 = 自由.lock().unwrap();let area = (*_heigth) * (*_自由);println!("Result: {}", area);
}

 

四、小结

  1. rust使用Arc替代Rc指针,以便在多线程下的共有安全
  2. rust使用Mutex互斥锁,保证独享资源
  3. 正确编写代码,避免竞争死锁
  4. 避免死锁,必须遵循一些原则,例如
    • 尽量减少一个线程同时持有多个锁的情况。如果一个线程确实需要持有多个锁,应该确保所有锁都按照相同的顺序被获取和释放
    • 使用尝试锁(TryLock)
    • 设置锁超时
    • 检测和恢复死锁

       避免死锁的方法,有多种,这里只能列出其中一二比较简单有效的实践。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/868136.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何使用宝塔面板修改网站缓存

缓存是提高网站加载速度和性能的重要手段。宝塔面板提供了多种缓存管理工具,帮助用户轻松配置和管理网站缓存。以下是具体步骤:步骤 描述登录宝塔面板 使用管理员账号登录到宝塔面板控制台。进入网站设置 在左侧菜单中选择“网站”,然后点击需要修改缓存的域名。打开缓存设置…

如何安全有效地重置Linux服务器的远程登录密码?

忘记Linux服务器的远程登录密码是一个常见的问题。为了确保您的服务器安全并顺利恢复访问权限,请按照以下步骤操作:提交工单请求密码重置:登录到服务商的管理后台,找到“主机租用/vps、云主机”选项。 选择“系统设置”,然后点击“服务器远程/WDCP管理账号密码重置/修改”…

网站存在非法信息,被系统拦截禁止访问

检查网站代码,确保没有被注入恶意代码。 联系程序提供商清理并修复程序漏洞。扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CSS3、Javascript等。承接:企业仿站、网站修改、网站改版、BUG修复、问题处理、二次开发、PSD…

域名解析失败的全面排查与解决方案

当您遇到新注册的域名无法解析的问题时,可能是由多个因素引起的。以下是详细的排查步骤和解决方案:确认域名注册成功:登录域名注册商的管理后台,确认域名已经成功注册并处于有效状态。 检查域名的有效期和状态,确保没有过期或被锁定。检查DNS解析设置:确认域名解析记录(…

新注册域名解析生效需要多长时间?

域名解析生效时间实名认证:首先,确保域名已经完成实名认证。这是在中国境内注册域名的必要步骤。 解析记录添加:在域名管理后台添加或修改解析记录后,解析生效的时间取决于多个因素。因素 影响说明运营商DNS 大部分运营商DNS可以在10-30分钟内生效,少数DNS可能需要1-3小时…

如何修改网站SQL中的密码?

修改网站数据库中的密码是一个常见的需求,尤其是在忘记管理员密码或需要增强安全性的情况下。以下是针对不同类型的网站(如WordPress、Joomla、Drupal、织梦等)修改数据库密码的具体步骤和注意事项。 一、通用步骤 1. 登录数据库管理工具使用phpMyAdmin:通过控制面板(如cP…

IDEA自定义注解配置

一、类注释 1、打开设置 打开设置:Settings->Editor->File and Code Templates,如下图。 File Header.java为引用的模板文件类头文件注释模板(File Header.java) /*** @title ${NAME}* @date ${DATE} ${TIME}* @author you-ni* @description TODO*/二、方法注释 1、打…

ASP.NET Core - 日志记录系统(二)

本篇接着上一篇 [ASP.NET Core - 日志记录系统(一)] 往下讲,所以目录不是从 1 开始的。2.4 日志提供程序 2.4.1 内置日志提供程序 ASP.NET Core 包括以下日志记录提供程序作为共享框架的一部分:Console Debug EventSource EventLog除此之外,还有一些微软官方提供的,但是没有…

bullyBox pg walkthrough Intermediate

nmap 发现80 和 22端口 访问80 端口发现 跳转 http://bullybox.local/ 在/etc/hosts 里面加上这个域名dirsearch 扫描的时候发现了.git泄露 用dunpall工具 获取.git泄露的源码查看源码 我们发现了数据库的密码 name => boxbilling, user => admin, password => Playin…

苹果系统下无痕检测是否开启iMessage服务,iMessages数据筛选,iMessage蓝号检测协议版

一、实现iMessage数据检测的两种方式:1.人工筛选,将要验证的号码输出到文件中,以逗号分隔。再将文件中的号码粘贴到iMessage客户端的地址栏,iMessage客户端会自动逐个检验该号码是否为iMessage账号,检验速度视网速而定。红色表示不是iMessage账号,蓝色表示iMessage账号。2…

数据分析之年度总结分享

背景:我们是一家国内的服装公司,在全国拥有几十家服装门店,从事18个服装品类的销售,市场覆盖国内上海、华北、华中、西南、东北、中南、西北七个区域,年销售额达数千万元。财年结束了,老板希望我们(数据分析师)能对公司的销售团队的数据进行分析,并得出结论作为下年度…

国家数据如何统一目录标识、统一身份登记和统一接口

日前,《国家数据基础设施建设指引》发布。最大的看点之一,是全国数据统一大市场:统一目录标识、统一身份登记和统一接口。那么,如何实现数据的全国统一目录标识、统一身份登记和统一接口? 一、全国统一目录标识 建立数据分类标准 顶层设计规划:由国家相关部门牵头,联合各…