Rust多线程交叉打印+Send Sync特征讲解

导航

    • Rust多线程交叉打印+Send Sync特征讲解
  • 一、Rust多线程交叉打印
  • 二、Send Sync 特征讲解

Rust多线程交叉打印+Send Sync特征讲解

一、Rust多线程交叉打印

  • 先说背景
  • 有两个线程,分别为0号线程1号线线程
  • 两个线程交叉打印共享值,并将共享值+1
  • 当标志为false时,0号线程打印,标志为true时,1号线程打印
  • 要求0号线程先打印

我们看代码

use std::sync::{Arc, Condvar, Mutex};
use std::thread;
static mut count: usize = 0;//全局变量
fn main() {//互斥锁,每次只让一个线程负责打印let mutex = Arc::new(Mutex::new(false));//初始值为false//信号量,实现线程同步,即控制线程运行顺序let condvar = Arc::new(Condvar::new());//让主线程等子线程执行完再推出let mut handles = vec![];for i in 0..=1 {//两个线程都应该持有同一个锁的所有权let cmutex = Arc::clone(&mutex);//两个线程都应该持有的事同一个信号量的所有权let ccondavar = Arc::clone(&condvar);let handle = thread::spawn(move || {//上锁,这个锁可能是0号线程先获得,也有可能是1号线程,这段代码要求0号线程先打印,所以我们下面通过信号量来实现let mut lock = cmutex.lock().unwrap();//print!("{}", *lock);for j in 0..=2 {if i % 2 == 0 {if *lock {//当mutex持有的值为false时才轮到0号线程打印,否则等待lock = ccondavar.wait(lock).unwrap();}*lock = true;//lock为false,0号线程可以打印一次,然后设置为true是为了防止0号线程一直打印unsafe {//count += 1;println!("{} thread ouput : {}", i, count);}ccondavar.notify_one();//通知1号线程可以行动了} else {if !*lock {//当mutex持有的值为true时才轮到1号线程打印,否则释放lock,然后等待lock = ccondavar.wait(lock).unwrap();}*lock = false;//lock为true时,0号线程可以打印一次,然后这里设置为false是为了防止0号线程一直打印unsafe {count += 1;println!("{} thread ouput : {}", i, count);}ccondavar.notify_one();//通知0号线程可以行动了}}});handles.push(handle);}for handle in handles {handle.join().unwrap();}}

运行一下

0 thread ouput : 1
1 thread ouput : 2
0 thread ouput : 3
1 thread ouput : 4
0 thread ouput : 5
1 thread ouput : 6
  • 可以看到我们已经实现了交叉打印,其实我们可以假想一下,如果一开始1号线程先抢到了Mutex,1号线程会先打印吗?
  • 答案是不会的,因为我们通过设置mutex的值为false,并在1号线程逻辑中的代码控制了,代码如下
if !*lock {//当mutex持有的值为true时才轮到1号线程打印,否则释放lock,然后等待lock = ccondavar.wait(lock).unwrap();}
  • 可以看到如果lock的初始值为false,信号量通过wait函数释放了这个锁,所以哪怕1号线程在最开始抢到了锁,也会在这里释放掉,让0号线程先打印

二、Send Sync 特征讲解

在Rust中,有一个很重要的机制就是所有权机制,值的赋值行为,很有可能导致一个值移动来移动去,使得在Rust的多线程编程中变得很难管理。

于此同时,多线程编程中,多个线程使用(拥有一个所有权)同一个变量的场景也是非常常见的,因为Rust提出了一个RcArc

RcArc一个共同特征:

  • 能够让一个值能有多个拥有者,即一个值,产生了多个所有权

但是RcArc一个重要的区别:

  • Arc能够在多线程中,安全的移动所有权,换句话说,让一个值的所有权可以移动到另一个线程中,这是因为Arc本身实现了Send特征,我们来看一下Send特征的定义

实现Send的类型可以在线程间安全的传递其所有权

unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}

第一部分代码中,可以看到我们需要实现线程的交叉打印,那必然线程之间是要共享一个锁,那么为了锁能够共享,那么我们需要对锁产生多个所有权,并且能够在线程之间移动所有权,所以第一份的代码中是这样:

let mutex = Arc::new(Mutex::new(false));//初始值为false

复制所有权和移动锁所有权的代码

 let cmutex = Arc::clone(&mutex);//复制所有权
 let ccondavar = Arc::clone(&condvar);let handle = thread::spawn(move || {//move移动所有权let mut lock = cmutex.lock().unwrap();

因此,多个线程,通过Arc,持有了同一个Mutex所有权,并且是每个线程都有一个所有权,可以共享使用Mutex

那么能够安全的传递Mutex的所有权能不能安全使用一个锁,是另一个特征Sync实现的,我们虽然安全的在多线程间移动所有权,但是能不能安全使用,还是需要实现Sync特征,所以Mutex本身实现了Sync特征。也看一下Sync特征的定义。

  • 实现Sync的类型可以在线程间安全的共享(通过引用)
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}

然后又可以看到,Mutex中,仅仅限制了其指向的值T只需要实现Send特征,这是因为锁的值,我们其实是想让线程每次单独的访问,所以在一个时刻只有一个线程访问即可,所有T需要Send,让一个时刻只有一个线程通过锁拿到值一个所有权

欢迎大家关注我的博客
在这里插入图片描述

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

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

相关文章

基于STM32的云端灌溉系统毕业设计

基于STM32的云端灌溉系统毕业设计 一、项目背景与意义 随着全球气候的变化和水资源短缺问题的日益严峻&#xff0c;传统的灌溉方式已不能满足现代农业发展的需求。智能灌溉系统以其节水、高效的特点逐渐成为研究的热点。本项目旨在设计一款基于STM32微控制器的云端灌溉系统&a…

Qt:网页嵌入与应用集成

这个专栏&#xff0c;主要用来记录分享一些使用Qt进行嵌入网页以及第三方应用相关技术的文章。本篇作为此专栏的快速导航。后续随着技术的不断研究和深入&#xff0c;会持续更新。 《QCefView&#xff08;1&#xff09;—— CMAKE项目、库文件生成和项目测试》 《QCefView&…

制鞋5G智能工厂数字孪生可视化平台,推进行业数字化转型

制鞋5G智能工厂数字孪生可视化平台&#xff0c;推进行业数字化转型。随着科技的飞速发展&#xff0c;5G技术与智能制造的结合正成为推动制鞋行业数字化转型的重要力量。制鞋5G智能工厂数字孪生可视化平台&#xff0c;不仅提高了生产效率&#xff0c;还优化了资源配置&#xff0…

2024.5.9 作业 xyt

1. 创建一对父子进程&#xff1a; 父进程负责向文件中写入 长方形的长和宽 子进程负责读取文件中的长宽信息后&#xff0c;计算长方形的面积 #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <…

从0开始linux(2)——热键、如何查阅手册

欢迎来到博主的专栏——从0开始linux 博主ID&#xff1a;代码小豪 博主使用的linux发行版&#xff1a;CentOS 7.6 文章目录 热键[Tab]热键Ctrl cshift[pageup]和[pagedown] 查阅手册\-\-help在线手册maninfo手册 热键 我们的命令行模式中存在很多的组合热键&#xff0c;这些按…

������森林消防泵:特点及使用场景 /恒峰智慧科技������

在大自然的怀抱中&#xff0c;森林是地球上最美丽的绿色家园。然而&#xff0c;森林火灾却时常威胁着这片美丽的家园。为了保护森林&#xff0c;我们有幸拥有了一支强大的森林消防泵队伍。今天&#xff0c;就让我们一起来了解一下这些守护者们的故事吧&#xff01; &#xfffd…

PAT 1041 Be Unique

原题链接&#xff1a;PAT 1041 Be Unique Being unique is so important to people on Mars that even their lottery is designed in a unique way. The rule of winning is simple: one bets on a number chosen from [1,10 4 ]. The first one who bets on a unique number…

电脑ip地址设置成什么比较好

随着信息技术的快速发展&#xff0c;IP地址已成为电脑在网络世界中的“身份证”。它不仅是电脑在网络中进行通信的基础&#xff0c;也直接关系到网络连接的稳定性、安全性和效率。然而&#xff0c;面对众多IP地址设置选项&#xff0c;许多用户可能会感到困惑。那么&#xff0c;…

创建JavaEE项目时,软件版本组合(Tomcat,JDK)

用Tomcat9&#xff0c;包名是javax.servlet-api 用Tomcat10或11&#xff0c;包名是jakarta.servlet-api 1 软件版本组合&#xff08;Tomcat&#xff0c;JDK&#xff09; 不是强制要求&#xff0c;只是创建项目一般这样选 1.1 JavaEE 8项目 Tomcat版本JDK版本JavaEE版本Tomc…

JavaWeb中的Session和Cookie

前言 什么是会话跟踪技术 Cookie 1.什么是cookie 2.Cookie的应用 2.1 保持用户登录状态 2.2 记录用户名 3. Cookie的设置和获取 3.1 、通过HttpServletResponse.addCookie的方式设置Cookie 3.2、浏览器中查看cookie的内容 3.3、服务端获取客户端携带的cookie&#xf…

华为eNSP学习—IP编址

IP编址 IP编址子网划分例题展示第一步:机房1的子网划分第二步:机房2的子网划分第三步:机房3的子网划分IP编址 明确:IPv4地址长度32bit,点分十进制的形式 ip地址构成=网络位+主机位 子网掩码区分网络位和主机位 学此篇基础: ①学会十进制与二进制转换 ②学会区分网络位和…

MySQL中的字符集陷阱:为何避免使用UTF-8

引言 在数据库管理中&#xff0c;理解字符集和编码是至关重要的。字符集定义了一组字符的编码规则&#xff0c;而编码则是将这些字符转换成计算机可识别的二进制形式的过程。MySQL作为最受欢迎的开源关系型数据库之一&#xff0c;在处理字符集和编码时也有其独特之处。 尽管U…

FPGA+海思ARM方案,可同时接收HDMI/VGA 两种信号,远程控制

FPGA海思ARM方案&#xff0c;可同时接收HDMI/VGA 两种信号&#xff0c;通过配置输出任一图像或者拼接后的图像 客户应用&#xff1a;无线远程控制 主要特性&#xff1a; 1.支持2K以下任意分辨率格式 2.支持H264压缩图像 3.支持WIFI/4G无线传输 4.支持自适应输入图像分辨率 …

光端机(2)——光纤通信学习笔记九

学习笔记里面只关注基本原理和概念&#xff0c;复杂的公式和推导都没有涉及 光端机 光发射机 作用&#xff1a;实现电光转换。将来自电端机的电信号对光源发出的光波进行调制&#xff0c;然后将调制好的光信号耦合到光线中传输。 基本性能要求 1.合适的发光波长&#xff08;光…

【信息系统项目管理师知识点速记】资源管理:管理团队

13.7 管理团队 管理团队是跟踪团队成员工作表现、提供反馈、解决问题并管理团队变更以优化项目绩效的过程。本过程的主要作用是,影响团队行为、管理冲突以及解决问题。本过程需要在整个项目期间开展。 管理项目团队需要借助多方面的管理和领导力技能,来促进团队协作、整合团…

GDAL:Warning 1: All options related to creation ignored in update mode

01 警告说明 首先贴出相关代码&#xff1a; out_file_name Rs_{:4.0f}{:02.0f}.tiff.format(year, month) out_path os.path.join(out_dir, out_file_name) mem_driver gdal.GetDriverByName(MEM) mem_ds mem_driver.Create(, len(lon), len(lat), 1, gdal.GDT_Float32) …

限时优惠||新算法转让(一种基于数学的元启发式算法)新的群智能算法转让,新的元启发式算法转让(独家发售)【仅售1份】

新算法 ||新算法转让、新的元启发式算法转让 ||一种基于数学开发的超隐喻的元启发式算法新算法 限时发售、限量1份 1️⃣完整的封装代码 2️⃣配套完整的灵感及数据 3️⃣测试集&#xff08;3个&#xff09; &#xff08;1&#xff09;cec2017&#xff08;10、30、50和100维&a…

HashMap前世今生

概述 HashMap是我们常用的一种数据结构&#xff0c;他是一个key-value结构。我们来深入了解一下。 1.8之前用的数组加链表 1.8之后用的数组加链表加红黑树&#xff0c;当链表数量大于8时&#xff0c;将链表转为红黑树。当红黑书节点小于6又会转为链表。 浅析HashMap的put()方…

揭秘:抽象类与接口之间的区别与意义

抽象类&#xff08;Abstract Class&#xff09;和接口&#xff08;Interface&#xff09;在Java等面向对象编程语言中都是用来定义对象的抽象行为&#xff0c;但它们之间存在一些重要的区别和不同的使用场景。以下是它们之间的主要区别和意义&#xff1a; 实现方式&#xff1a…

深入理解网络原理5----HTTP协议

文章目录 一、HTTP协议格式二、HTTP请求2.1 URL 基本格式2.2 URL encode2.3 "方法" (method)2.4 认识请求 "报头" (header) 三、HTTP 响应3.1 "状态码" (status code) 四、HTPPS工作过程&#xff08;经典面试题&#xff09; 提示&#xff1a;以下…