消息传递

实例

  1. use std::sync::mpsc;
  2. use std::thread;
  3. // 使用通道在多个线程中传递消息
  4. fn main() {
  5. let (tx, rx) = mpsc::channel();
  6. thread::spawn(move || {
  7. // send 函数会获取其参数的所有权
  8. // 并移动这个值归接收者所有
  9. let v = vec![7, 8, 9];
  10. for i in v {
  11. tx.send(i).unwrap();
  12. }
  13. });
  14. let recver = thread::spawn(move || {
  15. // 使用迭代方式从通道中取值
  16. for i in rx {
  17. println!("{}", i);
  18. }
  19. });
  20. recver.join().unwrap();
  21. }

共享状态

使用互斥器(Mutex)来保护数据,每次访问数据需要获取所锁:
Mutex<T>是一个智能指针
lock()调用 返回 一个叫做 MutexGuard智能指针, 这个智能指针实现了Deref来指向其内部数据;其也提供了一个Drop实现当MutexGuard离开作用域时自动释放锁

结合Arc

它是一个原子引用计数atomically reference counted)类型

适用于多线程场景

Rc<T>对比:

Arc<T>对应Rc<T>,提供引用计数功能
Mutex<T>对应RefCell<T>,提供内部可变性功能

实例

  1. use std::{
  2. sync::{Arc, Mutex},
  3. thread::{self, JoinHandle},
  4. };
  5. // 使用mutex在多线程中共享数据
  6. fn main() {
  7. // 创建具有多所有权的互斥器
  8. let m = Arc::new(Mutex::new(0));
  9. // 存放线程的handle
  10. let mut handles: Vec<JoinHandle<()>> = Vec::new();
  11. for _ in 0..10 {
  12. let counter = m.clone();
  13. // 在单独的线程中对互斥器进行修改
  14. let handle = thread::spawn(move || {
  15. // 调用 lock 后返回的是 MutexGuard 类型的智能指针
  16. // 来访问内部数据
  17. // 类似于 RefCell, 提供了内部可变性
  18. let mut num = counter.lock().unwrap();
  19. *num += 1;
  20. });
  21. handles.push(handle);
  22. }
  23. for handle in handles {
  24. handle.join().unwrap();
  25. }
  26. println!("{:?}", *m.lock().unwrap());
  27. }

Send,Sync trait

Send

Send标记trait表明类型的所有权可以在线程间传递。

几乎所有的Rust类型都是Send的,但是Rc<T>是不能Send的,这两个线程都可能同时更新引用计数。

任何完全由Send的类型组成的类型也会自动被标记为Send

几乎所有基本类型都是Send的,除了裸指针(raw pointer)。

Sync

Sync标记trait表明一个实现了Sync的类型可以安全的在多个线程中拥有其值的引用。

如果&TT的引用)是Send的话T就是Sync的,这意味着其引用就可以安全的发送到另一个线程

基本类型是Sync的,完全由Sync的类型组成的类型也是Sync的。

实例

直接往std::thread::spawn()里面传引用会报错:borrowed value does not live long enough

这里使用crossbeam库,不过需要多套一层thread::scope

  1. use crossbeam::thread;
  2. fn main() {
  3. let mut greeting = String::from("Hello");
  4. let greeting_ref = &greeting;
  5. thread::scope(|scoped_thread| {
  6. // spawn 3 threads
  7. for n in 1..=3 {
  8. // greeting_ref copied into every thread
  9. scoped_thread.spawn(move |_| {
  10. println!("{} {}", greeting_ref, n); // prints "Hello {n}"
  11. });
  12. }
  13. // line below could cause UB or data races but compiler rejects it
  14. // greeting += " world"; // ❌ cannot mutate greeting while immutable refs exist
  15. });
  16. // can mutate greeting after every thread has joined
  17. greeting += " world"; // ✅
  18. println!("{}", greeting); // prints "Hello world"
  19. }