• Rust 多线程编程


    一个进程一定有一个主线程,主线程之外创建出来的线程称为子线程
    多线程编程,其实就是在主线程之外创建子线程,让子线程和主线程并发运行,完成各自的任务。
    Rust语言支持多线程编程。

    Rust语言标准库中的 std::thread 模块用于多线程编程。
    std::thread 提供很很多方法用于创建线程、管理线程和结束线程。

    一、创建线程

    使用std::thread::spawn()方法创建一个线程。

    pub fn spawn(f: F) -> JoinHandle
    
    • 1

    参数 f 是一个闭包,是线程要执行的代码。

    范例

    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));
         }
    }
    编译运行结果如下
    hi number 1 from the main thread!
    hi number 1 from the spawned thread!
    hi number 2 from the main thread!
    hi number 2 from the spawned thread!
    hi number 3 from the main thread!
    hi number 3 from the spawned thread!
    hi number 4 from the spawned thread!
    hi number 4 from the main thread!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    咦,执行结果好像出错了? 是吗?
    当主线程执行结束,那么就会自动关闭创建出来的子线程。
    上面的代码,我们调用 thread::sleep() 函数强制线程休眠一段时间,这就允许不同的线程交替执行。
    虽然某个线程休眠时会自动让出cpu,但并不保证其它线程会执行。这取决于操作系统如何调度线程。
    这个范例的输出结果是随机的,主线程一旦执行完成程序就会自动退出,不会继续等待子线程。这就是子线程的输出结果不全的原因。

    二、让主线程等待子线程

    默认情况下,主线程并不会等待子线程执行完毕。为了避免这种情况,我们可以让主线程等待子线程执行完毕然后再继续执行。

    Rust标准库提供了 join() 方法用于把子线程加入主线程等待队列。

    spawn(f: F) -> JoinHandle
    
    • 1

    范例

    use std::thread;
    use std::time::Duration;
    fn main() {
         let handle = 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));
         }
         handle.join().unwrap();
    }
    编译运行结果如下
    hi number 1 from the main thread!
    hi number 1 from the spawned thread!
    hi number 2 from the spawned thread!
    hi number 2 from the main thread!
    hi number 3 from the spawned thread!
    hi number 3 from the main thread!
    hi number 4 from the main thread!
    hi number 4 from the spawned thread!
    hi number 5 from the spawned thread!
    hi number 6 from the spawned thread!
    hi number 7 from the spawned thread!
    hi number 8 from the spawned thread!
    hi number 9 from the spawned thread!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    从输出结果来看,主线程和子线程交替执行。
    主线程等待子线程执行完毕是因为调用了 join() 方法。

    三、move强制所有权迁移

    这是一个经常遇到的情况:
    实例

    use std::thread;
    fn main() {
        let s = "hello";
       
        let handle = thread::spawn(|| {
            println!("{}", s);
        });
    
        handle.join().unwrap();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在子线程中尝试使用当前函数的资源,这一定是错误的!因为所有权机制禁止这种危险情况的产生,它将破坏所有权机制销毁资源的一定性。我们可以使用闭包的move关键字来处理:
    实例

    use std::thread;
    fn main() {
        let s = "hello";
       
        let handle = thread::spawn(move || {
            println!("{}", s);
        });
    
        handle.join().unwrap();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四、消息传递

    使用通道传递消息,通道有两部分组成,一个发送者(transmitter)和一个接收者(receiver)。
    std::sync::mpsc包含了消息传递的方法:
    实例

    use std::thread;
    use std::sync::mpsc;
    fn main() {
        let (tx, rx) = mpsc::channel();
        thread::spawn(move || {
            let val = String::from("hi");
            tx.send(val).unwrap();
        });
        let received = rx.recv().unwrap();
        println!("Got: {}", received);
    }
    运行结果:
    Got: hi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    子线程获得了主线程的发送者tx,并调用了它的send方法发送了一个字符串,然后主线程就通过对应的接收者rx接收到了。

  • 相关阅读:
    成为会带团队的技术人 做规划:除了交付和稳定性,还要规划什么?
    vue slot插槽
    [尚硅谷React笔记]——第8章 扩展
    【JAVA】-- 简易超市管理系统窗口(三)(实现思路+每步代码)
    全渠道客服体验:Rocket.Chat 的无缝互动 | 开源日报 No.41
    [航海协会]摆
    帆软FineReport 报表联动
    什么是云渲染?【谈谈云渲染和传统渲染农场的区别】
    x6.js 从流程图组件库中拖拽组件到画布dnd使用
    计算机毕业设计 基于SpringBoot的车辆网位置信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
  • 原文地址:https://blog.csdn.net/inxunxun/article/details/133473197