Rust 编程语言 - 无畏并发

使用线程同时运行代码

多线程会遇到的问题:

  • 竞态条件
  • 死锁
  • 只在特定条件下发生,难以复现和修复的bug

rust 标准库使用1:1实现线程。一个语言级别的线程对应一个操作系统线程

创建线程

使用 thread::spawn创建线程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
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));
    }
}

等待线程终止

使用 join 方法等待线程终止

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
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));
        }
    });

// 等待线程结束后执行main方法 
    handle.join().unwrap();
    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }

}

传递参数

使用move 关键字,强制将依赖的参数的所有权交给线程内部

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
use std::thread;

fn main() {
    let v = vec![1, 2, 3];

    let handle = thread::spawn(move || {
        println!("Here's a vector: {:?}", v);
    });

    handle.join().unwrap();
}

使用消息传递

go 思想:不要通过共享内存来通讯;而是通过通讯来共享内存。

 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
use std::sync::mpsc;
use std::thread;

// mpsc 产出可以支持多个生产者,一个消费者
fn main() {
    let (tx, rx) = mpsc::channel();

    // rx 可以通过clone 实现多个生产者
    thread::spawn(move || {
        let val = String::from("hi");
        // tx 是生产端
        tx.send(val).unwrap();

        // 之后val 不可再被使用,所有权被移动到接收者
    });

    // 接收端 阻塞接收
    // rx.try_recv 非阻塞接收
    let received = rx.recv().unwrap();
    println!("Got: {}", received);

    // 迭代器接收
    // for received in rx {
    //     println!("Got: {}", received);
    // }
}

共享状态

互斥锁

使用规则:

  • 在使用数据之前尝试获取锁
  • 处理完被互斥器所保护的数据之后,必须解锁数据
 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
use std::sync::{Arc, Mutex};
use std::sync::Mutex;
use std::thread;

fn main() {
    // 使用Arc 使用多线程安全的多所有权
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Rc::clone(&counter);
        let handle = thread::spawn(move || {
        // 阻塞调用,直到拿到锁
            let mut num = counter.lock().unwrap();

            *num += 1;
        // 包含drop 方法,离开作用域自动释放锁
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Result: {}", *counter.lock().unwrap());
}

相关文章

0%