Rust 多线程编程

一个进程一定有一个主线程,主线程之外创建出来的线程称为子线程

多线程编程,其实就是在主线程之外创建子线程,让子线程和主线程并发运行,完成各自的任务。

Rust语言支持多线程编程。

Rust语言标准库中的 std::thread 模块用于多线程编程。

std::thread 提供很很多方法用于创建线程、管理线程和结束线程。

一、创建线程

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

复制代码
pub fn spawn<F, T>(f: F) -> JoinHandle<T>

参数 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!

咦,执行结果好像出错了? 是吗?

当主线程执行结束,那么就会自动关闭创建出来的子线程。

上面的代码,我们调用 thread::sleep() 函数强制线程休眠一段时间,这就允许不同的线程交替执行。

虽然某个线程休眠时会自动让出cpu,但并不保证其它线程会执行。这取决于操作系统如何调度线程。

这个范例的输出结果是随机的,主线程一旦执行完成程序就会自动退出,不会继续等待子线程。这就是子线程的输出结果不全的原因。

二、让主线程等待子线程

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

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

复制代码
spawn<F, T>(f: F) -> JoinHandle<T>

范例

复制代码
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!

从输出结果来看,主线程和子线程交替执行。

主线程等待子线程执行完毕是因为调用了 join() 方法。

三、move强制所有权迁移

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

实例

复制代码
use std::thread;
fn main() {
    let s = "hello";
   
    let handle = thread::spawn(|| {
        println!("{}", s);
    });

    handle.join().unwrap();
}

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

实例

复制代码
use std::thread;
fn main() {
    let s = "hello";
   
    let handle = thread::spawn(move || {
        println!("{}", s);
    });

    handle.join().unwrap();
}

四、消息传递

使用通道传递消息,通道有两部分组成,一个发送者(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

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

相关推荐
Tender_光6 分钟前
DNS域名解析服务
运维·服务器
白总Server8 分钟前
Nginx 中间件
大数据·linux·运维·服务器·nginx·bash·web
红尘散仙27 分钟前
六、WebGPU 基础入门——Vertex 缓冲区和 Index 缓冲区
前端·rust·gpu
苏近之30 分钟前
深入浅出 Rust 异步运行时原理
rust·源码
红尘散仙1 小时前
四、WebGPU 基础入门——Uniform 缓冲区与内存对齐
前端·rust·gpu
lllsure3 小时前
SpringCloud——负载均衡
服务器·网络·spring cloud
用户867132495743 小时前
5 个开源 MCP 服务器,让您的 AI 代理势不可挡
服务器
杨凯凡3 小时前
Linux安全防护:全方位服务安全配置指南
linux·运维·服务器·安全
Nightwish53 小时前
Linux随记(十七)
linux·运维·服务器
大卫小东(Sheldon)4 小时前
魔方求解器桌面版(层先法,基于Tauri实现)
rust