
17.1 线程

17.1.1 spawn:创建新线程
thread::spawn:创建一个新线程,需要传递一个闭包,并在其中包含希望在新线程运行的代码thread::sleep:调用强制线程停止执行一小段时间。比如:thread::sleep(Duration::from_millis(1));

17.1.2 join:等待所有线程结束
thread::spawn的返回值类型是JoinHandle,JoinHandle是一个拥有所有权的值JoinHandle.join:通过调用handle的join会阻塞当前线程直到handle所代表的线程结束(也就是等待所关联的线程运行结束)join的调用位置会影响线程的运行顺序(比如:影响线程是否同时运行)


17.1.3 线程与 move 闭包
- 可以在参数列表前使用
move关键字强制闭包获取其使用的环境值的所有权。比如:使用main函数中的外部数据,这样就无法知道这些外部数据的生命周期,因此无法编译 move关键字经常用于传递给thread::spawn的闭包,因为闭包会获取从环境中取得的值的所有权,因此会将这些值的所有权从一个线程传送到另一个线程move关键字覆盖了 Rust 默认保守的借用,但它不允许我们违反所有权规则



17.2 使用消息传递在线程间传送数据
17.2.1 消息传递(message passing)与信道(channel)
use std::sync::mpsc;:mpsc是 多个生产者,单个消费者(multiple producer, single consumer)的缩写。简而言之,Rust 标准库实现信道的方式意味着一个信道可以有多个产生值的 发送(sending)端,但只能有一个消费这些值的 接收(receiving)端mpsc::channel函数返回一个元组:第一个元素是发送端(发送者,tx),而第二个元素是接收端(接收者,rx,具有迭代器特性)- 发送者方法:
send(转移所有权) send(转移所有权):用来获取需要放入信道的值;该方法返回一个 Result<T, E> 类型,所以如果接收端已经被丢弃了,将没有发送值的目标,所以发送操作会返回错误- 接收者方法:
recv、try_recv recv:该方法会阻塞主线程执行直到从信道中接收一个值(即:一直等待消息,直到接收到一个值才会结束)。一旦发送了一个值,recv会在一个Result<T, E>中返回它。当信道发送端关闭,recv会返回一个错误表明不会再有新的值到来了try_recv:不会阻塞,相反它立刻返回一个 Result<T, E>:Ok 值包含可用的信息,而 Err 值代表此时没有任何消息。如果线程在等待消息过程中还有其他工作时使用 try_recv 很有用



17.2.2 信道与所有权转移
send:函数获取其参数的所有权并移动这个值归接收者所有

17.2.3 发送多个值并观察接收者的等待
- 接收者
rx是一个迭代器

17.2.4 通过克隆发送者来创建多个生产者
- 注意:下面的例子,是不确定顺序的实现!可以添加
join来阻塞线程,进而控制接收消息的先后顺序


17.3 共享状态并发

17.3.1 互斥器一次只允许一个线程访问数据
- 互斥器(mutex)在任意时刻只允许一个线程访问某些数据。为了访问互斥器中的数据,线程首先需要通过**获取互斥器的 锁(lock)**来表明其希望访问数据

17.3.2 互斥器 Mutex<T>
use std::sync::Mutex;Mutex<T>:使用关联函数new来创建一个Mutex<T>,Mutex<T>是一个智能指针;Mutex<T>提供了内部可变性,就像 Cell 系列类型那样lock:获取锁,以访问互斥器中的数据,返回一个叫做MutexGuard的智能指针(这个智能指针实现了Deref来指向其内部数据;其也提供了一个Drop实现当MutexGuard离开作用域时自动释放锁)。这个调用会阻塞当前线程,直到我们拥有锁为止- 锁的特性,如下所示
- 如果另一个线程拥有锁,并且那个线程 panic 了,则 lock 调用会失败。在这种情况下,没人能够再获取锁(所以这里可以选择
unwrap并在遇到这种情况时使线程panic) - 一旦获取了锁,就可以将返回值视为一个其内部数据的可变引用了(在示例中,
m的类型是Mutex<i32>而不是i32,所以必须获取锁才能使用这个i32值)

17.3.3 在线程间共享 Mutex<T>(一):不能将锁的所有权移动到多个线程中

17.3.4 在线程间共享 Mutex<T>(二):多线程和多所有权
Rc<T>并不能安全的在线程间共享


17.3.5 在线程间共享 Mutex<T>(三):原子引用计数 Arc<T>
Arc<T>:原子引用计数(atomically reference counted)类型,一个类似Rc<T>并可以安全的用于并发环境的类型。Arc<T>和Rc<T>有着相同的 APIMutex<T>提供了内部可变性,就像 Cell 系列类型那样,因此如同使用RefCell<T>可以改变Rc<T>中的内容那样,同样的可以使用Mutex<T>来改变Arc<T>中的内容

17.3.6 RefCell<T>/Rc<T> 与 Mutex<T>/Arc<T> 的相似性

17.4 使用 Sync 和 Send trait 的可扩展并发
17.4.1 通过 Send 允许在线程间转移所有权
Sendtrait(所有权):一个实现了Send的类型值的所有权可以在线程间传送Send的类型:几乎所有的 Rust(基本)类型都是Send的、完全由Send的类型组成的类型也会自动被标记为Send、Arc<T>- 非
Send的类型::Rc<T>、裸指针(raw pointer)

17.4.2 Sync 允许多线程访问
Synctrait(引用):一个实现了Sync的类型可以安全的在多个线程中拥有其值的引用Sync的类型:基本类型是Sync的、完全由Sync的类型组成的类型也是Sync的、Mutex<T>- 非
Sync的类型:Rc<T>、RefCell<T>、Cell<T>

17.4.3 手动实现 Send 和 Sync 是不安全的
- 注意:通常并不需要手动实现
Send和Synctrait!

17.5 小结




















