线程 (Threads)

在我们开始写多线程代码之前,先退一步谈谈线程是什么、我们为什么要用它。

什么是线程?(What is a thread?)

线程 (thread) 是由底层操作系统管理的执行上下文。
每个线程有自己的栈和指令指针 (instruction pointer)。

一个进程 (process) 可以管理多个线程。 这些线程共享同一片内存空间,意味着它们可以访问同样的数据。

线程是逻辑 (logical) 构造。最终,CPU 核心(物理 (physical) 执行单元)一次只能运行一组指令。
由于线程数可能远多于 CPU 核心数,操作系统的调度器 (scheduler) 负责决定在任意时刻运行哪个线程,把 CPU 时间在它们之间划分以最大化吞吐量和响应性。

main

Rust 程序启动时,运行在单个线程上——主线程 (main thread)
这个线程由操作系统创建,负责运行 main 函数。

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

fn main() {
    loop {
        thread::sleep(Duration::from_secs(2));
        println!("Hello from the main thread!");
    }
}

std::thread

Rust 标准库提供了 std::thread 模块,允许你创建和管理线程。

spawn

可以用 std::thread::spawn 创建新线程并在其上执行代码。

例如:

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

fn main() {
    let handle = thread::spawn(|| {
        loop {
            thread::sleep(Duration::from_secs(1));
            println!("Hello from a thread!");
        }
    });
    
    loop {
        thread::sleep(Duration::from_secs(2));
        println!("Hello from the main thread!");
    }
}

如果你在 Rust playground 上执行这段程序, 你会看到主线程和被 spawn 出来的线程并发运行,各自独立地推进。

进程终止 (Process termination)

主线程结束时,整个进程也会退出。
被 spawn 的线程会一直运行,直到它自己结束或主线程结束。

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

fn main() {
    let handle = thread::spawn(|| {
        loop {
            thread::sleep(Duration::from_secs(1));
            println!("Hello from a thread!");
        }
    });

    thread::sleep(Duration::from_secs(5));
}

上面的例子中,你应当能看到 "Hello from a thread!" 大约被打印 5 次。
然后主线程结束(sleep 调用返回时),而被 spawn 的线程也会因为整个进程退出而被终止。

join

你也可以通过对 spawn 返回的 JoinHandle 调用 join 方法来等待 spawn 的线程结束。

use std::thread;
fn main() {
    let handle = thread::spawn(|| {
        println!("Hello from a thread!");
    });

    handle.join().unwrap();
}

这个例子里,主线程会等被 spawn 的线程完成后再退出。
这就在两个线程之间引入了一种同步 (synchronization) 形式:你可以确保程序退出之前一定能看到 "Hello from a thread!",因为主线程要等到被 spawn 的线程结束才会退出。

原文链接:英文原文