Rust- 多线程

2023-11-08

Rust’s standard library provides support for native threads with its std::thread module, allowing you to run code in parallel. When programming in Rust, you have a high degree of control over threads, but this comes with an added layer of complexity.

Here’s an example of how to create a new thread in Rust:

use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

In this example, we use the thread::spawn function to create a new thread. The code to be run in the new thread is placed inside a closure.

use std::thread;
use std::time::Duration;

fn main() {
    /*
        创建线程 std::thread::spawn();
     */

    // Case1: 主线程结束,即使子线程没有执行完毕也要结束
    thread::spawn(|| {
        for i in 1..10 {
            println!("子线程{}", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("主线程{}", i);
        thread::sleep(Duration::from_millis(1));
    }

    // thread::sleep()会让线程睡眠一段时间,某个线程睡眠的时候,让出CPU,
    // 可以让不同的线程交替执行,这要看操作系统如何调度线程

    // Case2:使用Join方法,等待子线程全部执行完毕再结束
    let handler = thread::spawn(|| {
        for i in 1..10 {
            println!("子线程{}", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("主线程{}", i);
        thread::sleep(Duration::from_millis(1));
    }
    handler.join().unwrap();
}

One major aspect of multi-threading in Rust is communication between threads. Rust provides several ways for threads to communicate and synchronize with each other, such as:

  1. Channels: Channels are a way of sending data between threads. They are provided by the std::sync::mpsc module (the mpsc stands for “multiple producer, single consumer”).

  2. Mutexes: Mutexes allow us to control access to shared data by ensuring that only one thread can access the data at any one time.

  3. Arcs: The Arc type, which stands for “atomic reference count”, is a type of smart pointer that allows multiple threads to safely share ownership of some data.

Finally, Rust’s ownership system extends to its handling of threads, ensuring that data races cannot occur. Rust enforces these rules at compile time, which eliminates a whole class of potential bugs related to thread safety.

1. Channels

Channels in Rust allow two or more threads to communicate with each other by transmitting a certain type of data from one thread to another. Rust provides the std::sync::mpsc module for this purpose. Here’s an example:

use std::sync::mpsc;
use std::thread;
fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let val = String::from("hello");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Got: {}", received);  // Got: hello
}

In this example, we’re creating a new channel with mpsc::channel(), then moving the transmitter end into a new thread and sending the string “hello” down the channel. The receiver end stays in the main thread and waits to receive the message.

2. Mutexes

Mutexes provide a mechanism to protect shared data. Here’s an example:

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 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());  // Result: 10
}

  In this example, we’re creating a counter inside a Mutex to protect access to this shared state. We’re then creating ten threads, each of which will get a lock on the Mutex and increment the counter. Let’s analyze this program in detail:

  1. Arc::new(Mutex::new(0)) creates a new atomic reference count (Arc) around a mutex that guards an integer (i32). The Arc is used so that the counter can be shared safely among multiple threads.

  2. A for loop is used to spawn 10 threads. For each iteration:

    • A clone of the Arc containing the counter is created. Cloning an Arc increases the reference count.

    • The cloned Arc is moved into the new thread.

    • The thread acquires a lock to the mutex (with counter.lock().unwrap()), which returns a mutable reference to the value inside the mutex (i.e., the counter).

    • The thread then increments the value the mutable reference points to (*num += 1), which is the value of the counter.

    • The thread then ends, the lock is released, and the Arc’s reference count is decreased.

  3. handles.push(handle); is used to store the join handle for each thread in a vector, so that we can later wait for all threads to finish execution.

  4. After the threads have been spawned, the main thread waits for all threads to finish by calling handle.join().unwrap(); for each handle in the vector.

  5. Finally, the main thread acquires a lock on the counter one more time to print the final value. Because each thread incremented the counter exactly once, and we waited for all threads to finish before printing, the output is “Result: 10”.

So the counter ends up being 10 because the number was incremented once in each of the 10 threads.

3. Arcs

Arc stands for Atomic Reference Counting. It’s a thread-safe reference-counting pointer, used when you need to share data between multiple threads. In the previous Mutex example, we used an Arc to share the Mutex between multiple threads.

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new(vec![1, 2, 3]));

    for _ in 0..3 {
        let data = Arc::clone(&data);
        thread::spawn(move || {
            let mut data = data.lock().unwrap();
            data[0] += 1;
        });
    }
}

In this example, we’re sharing a Mutex<Vec<u32>> among multiple threads. Without the Arc, Rust’s ownership rules would prevent us from moving the Mutex into more than one thread.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rust- 多线程 的相关文章

随机推荐

  • stm32之IIC协议

    主要通过两个层面来讲 物理层 协议层 IIC是一个同步半双工串行总线协议 一 物理层 通信模型 1 最早是飞利浦公司开发的这个协议 最早应用到其产品上去 2 两线制 两根信号线 其中SCL为时钟线 SDA为数据线 3 挂载在IIC总线上的设
  • 在SQL Server中从所有表或所有数据库中搜索关键字

    从所有表及所有库中搜索关键字 在所有表中搜索关键字 declare str varchar 100 set str a 要搜索的字符串 declare s varchar 8000 declare tb cursor local for s
  • 【100%通过率 】【华为OD机试 c++/java/python】计算数组中心位置【 2023 Q1

    华为OD机试 题目列表 2023Q1 点这里 2023华为OD机试 刷题指南 点这里 题目描述 给你一个整数数组nums 请计算数组的中心位置 数组的中心位置是数组的一个下标 其左侧所有元素相乘的积等于右侧所有元素相乘的积 数组第一个元素的
  • aws-msk-托管kafka集群的简单使用(VPC内部访问:无验证和SASL认证)

    1 使用控制台创建即可 根据实例类型创建需要至少15分以上 可以提前创建好ec2实例和Secrets Manager 一会会使用到 2 创建Secrets Manager 使用无认证时请跳过 官方文档 https docs aws amaz
  • 基础算法题——Classical String Problem(字符环)

    Classical String Problem 题意 给定字符串S由小写字母组成 执行Q次操作 每个操作都可以是以下两种类型之一 M 修改 给定一个整数x 您需要根据x的值修改S 如果x是正的 则将 S 字符串中左边的 x 个字母移动到S
  • [k8s] pod的创建过程

    pod的创建过程 定义 Pod 的规范 apiVersion v1 kind Pod metadata name my pod spec containers name my container image nginx latest 创建
  • lnmp 域名绑定与设置

    该文字转载自 https lnmp org faq lnmp vhost add howto html 感谢广大网友的分享 一般情况下每个虚拟主机就是一个网站 网站一般通过域名进行访问 本文为教程适合LNMP 1 2 各个版本的添加过程基本
  • 恒玄BES调试笔记-BES2500如何修改RF回连功率

    修改路径如下 platform drivers bt best2300a bt drv rfconfig c 可以通过以上截图 写固定的某个值 比如0x18f 写0xaf为RF回连功率调整0dB 这个寄存器具体的BES2500 RF Reg
  • 记录使用git时碰到的问题及解决办法

    fatal refusing to merge unrelated histories git pull allow unrelated histories 本地和github上分别生成了master和main分支 四步 参考https z
  • js弹出框、对话框、提示框、弹窗总结

    一 JS的三种最常见的对话框 JS最常用三种弹出对话框 弹出对话框并输出一段提示信息 function ale 弹出一个对话框 alert 提示信息 弹出一个询问框 有确定和取消按钮 function firm 利用对话框返回的值 true
  • 架构核心技术之微服务架构

    小熊学Java https www javaxiaobear cn 文末有免费资源 本文我们来学习微服务的架构设计 主要包括如下内容 单体系统的困难 编译部署困难 数据库连接耗尽 服务复用困难 新增业务困难 微服务框架 Dubbo 和 Sp
  • strerror函数运行时报错 Segmentation fault (core dumped)

    虽然编译时没报错 但还是要加上以下头文件 include
  • 优化SQL之最佳索引

    SQL优化工具Tosska SQL Tuning Expert for Oracle 帮助SQL开发人员解决SQL性能问题 本工具主要创始人Richard To 资深ITPUB元老 从1996年开始设计SQL优化工具 拥有超过20年的SQL
  • css核心知识点攻坚指南

    css核心知识点攻坚指南 一 什么是CSS 层叠样式表 英文全称 Cascading Style Sheets 是一门专门用来描述 html xml 等文件样式的一门语言 简而言之 我们可以通过编写css来描述当前文档的样式规则 让页面的展
  • Java Swing实现Mybatis3代码生成器,使用jtattoo第三方java Swing美化包

    项目介绍 代码生成器 目前只支持MySQL 其他的数据库需要在代码中修改部分配置以及更换JDBC驱动 整个项目从MySQL数据库连接测试 创建数据库 导入SQL脚本 保存基本配置 生成最后代码 适合初学swing的开发人员 本项目使用jta
  • 电巢科技出席第26届西北地区电子技术与线路课程教学改革研讨会,聚焦一流课程建设!

    2023年9月15日至17日 北方民族大学召开第26届西北地区电子技术与线路课程教学改革研讨会 本次会议围绕 梳理课程教学内容 改革教学方式 探索虚拟教研室构建方式 完善基层教学组织 推进一流课程和一流教材资源共享 提高课程教学质量 这些主
  • SpringBoot自动配置理解

    首先 所有的启动类中都有一个 SpringBootApplication注解 放置在Springboot启动类上 表明该类是开启Springboot容器的入口 它是一个复合注解 里面包含了包扫描 自动注入 配置注入的功能 按Ctrl 鼠标左
  • 4个快速查找Linux历史命令的技巧(history)

    history 法1 光标上下键 法2 ctrl r 输入某条命令的关键字 找出来对应的命令 按右光标键 法3 数字 执行历史命令中第N条命令 法4 字符串 搜索历史命令中最近一个以xxxx字符开头的命令 例如 vim
  • C练题笔记之:Leetcode-307. 区域和检索 - 数组可修改

    题目 给你一个数组 nums 请你完成两类查询 其中一类查询要求 更新 数组 nums 下标对应的值 另一类查询要求返回数组 nums 中索引 left 和索引 right 之间 包含 的nums元素的 和 其中 left lt right
  • Rust- 多线程

    Rust s standard library provides support for native threads with its std thread module allowing you to run code in paral