Rust线程间通信通讯channel的理解和使用

Channel允许在Rust中创建一个消息传递渠道,它返回一个元组结构体,其中包含发送和接收端。发送端用于向通道发送数据,而接收端则用于从通道接收数据。不能使用可变变量的方式,线程外面修改了可变变量的值,线程里面是拿不到最新的值的。

不可用方式

is_loading在主线程里面,通过参数传递给子线程,等待5秒之后,主线程里面的is_loading修改为false,但是子线程里面获取不到最新的值,是由于所有权和线程安全性的限制所导致的。所以会导致子线程一直运行:

use std::io::{self, Write};
use std::thread;
use std::time::Duration;fn main() {let mut is_loading = true;// creat close package must use move to get is_loadingthread::spawn(move || { sub_loading(&is_loading) });// sleep 3 second then stop loadingthread::sleep(Duration::from_secs(5));// set loading stopis_loading = false;loop {thread::sleep(Duration::from_millis(250));print!("build done");}
}fn sub_loading(flag: &bool) {let loading_chars = vec!['-', '\\', '|', '/'];let mut index = 0;// cant get newe valuewhile *flag {print!("\rLoading {} {} ", flag, loading_chars[index]);io::stdout().flush().unwrap();index = (index + 1) % loading_chars.len();thread::sleep(Duration::from_millis(250));}
}

Channel通道说明

每个channel由两部分组成:发送端(Sender)和接收端(Receiver)。  发送端用于向channel发送消息,而接收端则用于接收这些消息。这种机制允许线程之间的安全通信,避免了共享内存的复杂性和潜在的数据竞争问题。 (通过通信来共享内存,而非通过共享内存来通信)  Rust的channel为线程间通信提供了一种安全、简单的方式,是构建并发应用的基础工具之一。channel是Rust标准库的一部分,自Rust 1.0版本以来就包含了这个功能。随着Rust语言和标准库的发展,channel的实现和API可能会有所改进,但其基本概念和用法保持一致。

基本步骤如下:

创建: 使用std::sync::mpsc::channel()函数创建一个新的channel,这个函数返回一个包含发送端(Sender)和接收端(Receiver)的元组。

发送: 使用发送端的send方法发送消息。send方法接受一个消息值,如果接收端已经被丢弃,会返回一个错误。

接收: 使用接收端的recv方法接收消息。recv会阻塞当前线程直到一个消息可用,或者channel被关闭。

最简单的一个使用demo:

use std::sync::mpsc;
use std::thread;fn main() {// 创建一个通道let (sender, receiver) = mpsc::channel();// 在主线程中发送数据let data = 42;sender.send(data).unwrap();// 创建子线程来接收数据let child_thread = thread::spawn(move || {let received_data = receiver.recv().unwrap();println!("Received data in child thread: {}", received_data);});child_thread.join().unwrap();
}

在Rust中,如果你想停止一个由thread::spawn创建的线程,你不能直接停止它,因为Rust没有提供直接的方式来停止线程。但是,你可以通过通信来请求线程优雅地停止运行。

如果想使用一种方式,让主线程控制子线程停止,就可以使用channel通道:

use std::sync::mpsc;
use std::thread;
use std::time::Duration;fn main() {let (tx, rx) = mpsc::channel();let child_thread = thread::spawn(move || {loop {// 检查是否收到停止信号if let Ok(_) = rx.try_recv() {println!("线程收到停止信号,正在退出...");break; // 退出循环,线程结束}// 执行线程的工作println!("sub child thread is ruing");// 为了演示,让线程休眠一会儿thread::sleep(Duration::from_secs(1));}println!("线程已退出。");});// 主线程等6秒,模拟耗时操作thread::sleep(Duration::from_secs(6));// 假设6秒后需要停止线程tx.send(()).unwrap(); // 发送停止信号// 等待线程退出child_thread.join().unwrap();
}

运行结果:

注意事项

recv:方法是阻塞的,即 它会阻塞当前线程, 直到从通道中接收到消息。 线程在调用rx.recv().unwrap()时会阻塞 等待消息的到来。一旦主线程通过tx.send(msg).unwrap();发送了消息,主线程会接收到这个消息并继续执行,之后程序才会正常退出。

try_recv:尝试在不阻塞的情况下返回此接收器上的挂起值。此方法永远不会为了等待数据可用而阻止调用方。相反,它将始终立即返回,并可能选择通道上的挂起数据。这对于在决定阻塞接收器之前进行“乐观检查”非常有用。

recv_timeout:尝试在此接收器上等待一个值,如果相应的通道已挂断或达到最后期限,则返回错误。如果没有可用的数据,并且可能发送更多的数据,此函数将始终阻止当前线程。将消息发送到相应的发件人(或SyncSender)后,此收件人将唤醒并返回该消息。如果相应的Sender已断开连接,或者在该呼叫被阻止时断开了连接,则该呼叫将唤醒并返回Err,以指示在此信道上无法再接收到消息。但是,由于通道是缓冲的,因此在断开连接之前发送的消息仍将被正确接收。

recv_deadline:返回一个迭代器,该迭代器将阻止等待消息,但永远不要惊慌!当频道挂断时,它将返回None。

iter:返回一个迭代器,该迭代器将尝试生成所有挂起的值。如果没有更多挂起的值或通道已挂起,它将返回None。迭代器永远不会死机!或者通过等待值来阻止用户。

关于MPSC讲解

其中mpsc是Multi producer, Single consumer FIFO queue的缩写,即多生产者单消费者先入先出队列。Rust标准库提供的channel是MPSC(多生产者,单消费者)模型,这意味着可以有多个发送端(Sender)向同一个接收端(Receiver)发送消息。这种模式非常适用于工作队列模型,其中多个生产者线程生成任务,而单个消费者线程处理这些任务。

除了MPSC之外,还有如下几种模型:

SPSC(Single Producer Single Consumer): 单生产者单消费者。

SPMC(Single Producer Multiple Consumer): 单生产者多消费者。

MPSC(Multi Producer Single Consumer): 多生产者单消费者, Rust中标准的mpsc模型。

MPMC(Multi Producer Multi Consumer)*: 多生产者多消费者。

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

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

相关文章

水果销售(源码+文档)

水果销售管理系统(小程序、ios、安卓都可部署) 文件包含内容程序简要说明含有功能项目截图客户端添加地址首页商品详细意见反馈待发货商品分类我的代付款我的地址搜索防骗指南资料修改登录注册 后端管理分类管理反馈管理订单管理商品管理用户管理 文件包…

OpenHarmony实战:轻量级系统之配置其他子系统

除上述子系统之外,还有一些必要但是无需进行移植的子系统。如:分布式任务调度子系统、DFX子系统。 这些子系统添加方式比较简单,在“vendor/MyVendorCompany/MyProduct/config.json”文件中进行如下配置即可: {"subsystem&…

vulhub中Apache Solr 远程命令执行漏洞复现(CVE-2019-0193)

Apache Solr 是一个开源的搜索服务器。Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现。此次漏洞出现在Apache Solr的DataImportHandler,该模块是一个可选但常用的模块,用于从数据库和其他源中提取数据。它具有一个功能&#…

[RK3128_LINUX5.1] 关于 RetroArch 使用

问题描述 查看文档 docs\cn\Linux\ApplicationNote\Rockchip_Use_Guide_Linux_RetroArch_CN.pdf,描述为实验 make menuconfig 后勾选选项 Libretro cores and retroarch -> retroarch 但是SDK中并没有这个选项 解决方案: 目前发布的buildroot SDK…

7 X 24h智能安全运维再升级!Fortinet 全面集成全新 FortiGuard SOCaaS

数字化时代网络安全威胁层出不穷,网络犯罪分子的狡诈攻击手段不断翻新,传统安全防御手段亟需进化。更为棘手的是,网络安全专业人才的匮乏,让众多企业陷入安全运营的困境。为了有效应对这一挑战,Fortinet全新推出FortiG…

使用PostgreSQL中的隐式转换解决,MybatisPlus插入数据库时的类型不一致的问题

使用PostgreSQL中的隐式转换解决,MybatisPlus插入数据库时的类型不一致的问题 问题描述 鄙人在使用 MybatisPlus插件开发一个SpringBoot项目时, 遇到数据库中employee表与Java实体对象中某个属性的类型不一致, 导致插入数据库失败. 具体问题截图如下: 具体原因在于, Java实体…

泛微E-Mobile /client.do 命令执行漏洞复现

0x01 产品简介 泛微e-Mobile移动管理平台是一款由泛微软件开发的企业移动办公解决方案。它提供了一系列功能和工具,使企业员工能够通过移动设备随时随地进行办公和协作。 0x02 漏洞概述 泛微E-Mobile存在命令执行漏洞,攻击者可以通过/client.do执行任意命令执行,从而获得…

Golang学习系列1-pprof性能调优

1. pprof 简述 一位亦师亦友的话让我记忆犹新,他说“学习一个新事务,应该从三个方面入手what,why,how;且三者的重要程度应该是递减”。所以在本文的第一部分先叙述下pprof的what & why。 1.1 What? pprof是golang自身提供的一种性能分…

C++初学者:优雅创建第一个窗口

我想学习C做一些实用的程序,但是我不想在软件界面上花太多的时间,可是每每就是界面影响我的思绪。 今天学习C类的包装知识,终于整出了一个我的界面类,虽然封装水平很弱, 这次就用这个类,写了自己工作上常用…

高阶DS---AVL树详解(每步配图)

目录 前言: AVL树的概念: AVL树节点的定义: AVL树的插入(重点) AVL树的旋转: (1)新节点插入较高左子树的左侧---右单旋 (2)新节点插入较高右子树的右侧---左单旋 …

续二叉搜索树递归玩法

文章目录 一、插入递归二、寻找递归&#xff08;非常简单&#xff0c;走流程就行&#xff09;三、插入递归&#xff08;理解起来比较麻烦&#xff09; 先赞后看&#xff0c;养成习惯&#xff01;&#xff01;&#xff01;^ _ ^<3 ❤️ ❤️ ❤️ 码字不易&#xff0c;大家的…

【基于HTML5的网页设计及应用】——-正则表达式.

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

ObjectiveC-09-OOP面向对象程序设计-继承

继承是所有高级语言都实现的一种特征&#xff0c;比如java、python甚至现在的js也有类似继承的写法。在表层目的是减少重复代码&#xff0c;深层目的是为了匹配业务与程序间的映射关系。 先来看下OOP设计思起中的继承的关系表示 再结合实例来看下完整的关系表示 一个简单的例…

10 年跟踪 Hacker News 招聘贴,解读科技行业变迁

Hackers News (HN) 是国外程序员最喜欢逛的论坛。能登上首页的帖子类似于上了新浪微博。因为其巨大的程序员访问量&#xff0c;因此也成为了公司招聘的渠道。久而久之 HN 招聘帖还形成了专门的标题格式 Ask HN: Who is hiring? 正好有人通过 Ask HN 来分析技术趋势&#xff0c…

【Blockchain】区块链浏览器 | 以太坊Etherscan比特币Blockchain门罗币Monero

区块链浏览器概述 区块链浏览器是一种软件,它使用API(应用程序编程接口)和区块链节点从区块链中提取各种数据&#xff0c;然后使用数据库来排列搜索到的数据&#xff0c;并以可搜索的格式将数据呈现给用户。 用户的输入是资源管理器上的可搜索项&#xff0c;然后通过数据库上…

《QT实用小工具·十》本地存储空间大小控件

1、概述 源码放在文章末尾 本地存储空间大小控件&#xff0c;反应电脑存储情况&#xff1a; 可自动加载本地存储设备的总容量/已用容量。进度条显示已用容量。支持所有操作系统。增加U盘或者SD卡到达信号。 下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #if…

数据库管理工具 DBeaverUE for Mac激活版

DBeaverUE for Mac是一款功能强大且易于使用的数据库管理工具&#xff0c;专为Mac用户设计。它支持多种数据库类型&#xff0c;如MySQL、PostgreSQL、Oracle等&#xff0c;使得用户可以轻松管理和操作各种数据库。 软件下载&#xff1a;DBeaverUE for Mac激活版下载 DBeaverUE …

【C语言】翻译环境与运行环境

一、前言 在我们学习C语言的时候&#xff0c;第一个接触的程序就是&#xff1a;在屏幕上打印” hello word! “&#xff0c;可当时的我们却未去深入的理解与感悟&#xff0c;一个程序代码是如何运行的&#xff1b;而这一期的博客&#xff0c;则是带着我们&#xff0c;通过C代码…

STM32的定时器中断Cubemx

STM32的定时器中断Cubemx 0.定时器简介1.配置时钟2.配置定时器3.创建工程4.补充源码 0.定时器简介 基本定时器功能&#xff1a; 16位向上、向下、向上/下自动装载计数器16位可编程(可以实时修改)预分频器&#xff0c;计数器时钟频率的分频系数为1&#xff5e;65535之间的任意…

向量旋转操作之分段递归交换

开篇 这是对于之前一维向量左旋操作问题的最后一个解法&#xff0c;也是关于这个问题的最后一篇文章。在之前的文章中&#xff0c;我们分别用求逆法、取模置换法对该问题进行了解答&#xff0c;今天&#xff0c;使用的是分段递归的方式。 问题概要 将一个n元一维向量向左旋转i个…