1. 概述

rust言语自身的并发特性较少,目前讲的并发特性都是来自规范库(而不是言语自身)。

其实咱们无需仅限于规范库的并发,能够自己完成并发。

但在rust言语中有两个并发概念:

  • std::marker::Syncstd::marker::Send这两个trait。

2. Send

Send:答应线程间搬运所有权。

  • 完成Send trait的类型能够在线程间搬运所有权,Rust中简直所有的类型都完成了Send
    • Rc<T>没有完成Send,它只用于单线程的场景。
  • 任何完全由Send组成的类型也被标记为Send
  • 实际上除了原始指针之外,简直所有的根底类型都完成了Send

例如:

use std::thread;
fn main() {
    let number = 5;
    let handle = thread::spawn(move || {
        println!("{}", number); // 这儿能够正常工作,由于number完成了Send trait
    });
    println!("{}", number);
    handle.join().unwrap();
}

咱们创建了一个新的线程,并把一个number变量移动到这个新线程中。这是由于number的类型(在这个例子中是i32)完成了Sendtrait,所以咱们能够安全地在两个线程之间搬运所有权的所有权。

3. Sync

Sync:答应从多线程一起拜访。

  • 完成Sync的类型能够安全的被多个线程引证
  • 也就是说:如果T完成了Sync,那么&T(T的引证)就是完成了Send
    • 表明T的引证能够被安全地送往另一个线程
  • 根底类型都完成了Sync
  • 完全由Sync类型组成的类型也是Sync
    • 但是Rc<T>不是Sync
    • RefCell<T>Cell<T>宗族也不是Sync
    • Mutex<T>完成了Sync
use std::sync::Arc;
use std::thread;
fn main() {
    let shared_data = Arc::new(Some(5)); // Arc封装了一个可同享的数据,并且能够安全地在多个线程之间同享。
    let handle = thread::spawn(move || {
        println!("{:?}", shared_data); // 这儿能够正常工作,由于Arc<T>完成了Sync trait
    });
    handle.join().unwrap();
}

咱们创建了一个新的线程,并测验在两个线程之间同享一个Arc<T>目标。这是由于Arc<T>(通过其内部的类型T)完成了Synctrait,所以咱们能够安全地在多个线程之间同享这个目标。

如果咱们测验在两个线程之间直接同享一个没有完成Sync的目标,Rust编译器会给出错误。

4. 手动完成Send和Sync很难确保安全

手动来完成Send和Sync是很难确保安全的,由于手动完成这些trait的时分涉及到使用特别不安全的Rust代码,你需求非常谨慎地确保设计,才能满意线程间的安全性要求。