返回介绍

11.3 同步

发布于 2024-10-13 11:25:32 字数 2899 浏览 0 评论 0 收藏 0

通道是单所有权,一旦值被发送,将无法再次使用。某些时候,内存共享有实际需求。标准库提供 互斥 用于资源和逻辑保护。但面对多线程共享时,需额外的 原子引用计数 来启用多所有权。

  • Arc : 共享所有权,并发安全的原子引用计数。
  • Mutex : 互斥锁,安全可变性( &mut T ),非递归锁。
  • RwLock : 读写锁( &T , &mut T )。
  • Atomic : 原子操作(内部可变性)。
  • Barrier : 设置屏障,让所有参与线程同时开始。
  • Condvar : 阻塞等待,直到条件变量发出通知。
  • Once : 单次执行。

将所有权交给 Mutex ,随后通过它的访问被互斥。没有解锁方法,临界区大小可通过作用域或调用 drop 调节。

如果没有要保护的数据,可使用 Mutex<()> ,像其他语言那样使用。

use std::thread;
use std::sync::{Mutex, Arc};

fn main() {
  let v = vec![1, 2, 3];
  let d = Mutex::new(v);   // move!
  
  {
    let mut p = d.lock().unwrap();
    p.push(4);
  } // unlock!
 
  {
    let mut p = d.lock().unwrap();  // lock or block!
    p.push(5);
  } // unlock!

  println!("{:?}", d);
}

// Mutex { data: [1, 2, 3, 4, 5], poisoned: false, .. }
fn main() {
  let v = vec![1, 2, 3];
  let d = Mutex::new(v);   // move!
  
  let mut p = d.lock().unwrap();
  p.push(4);
  drop(p);
 
  let mut p = d.lock().unwrap();
  p.push(5);
  drop(p);

  println!("{:?}", d);
}

// Mutex { data: [1, 2, 3, 4, 5], poisoned: false, .. }

在智能指针一节中,我们用 Rc<RefCell> 来实现可变所有权共享,但那不是并发安全的。

可以说, Arc<Mutex>RefCell 并发版本,而 AtomicCell 并发版本。

use std::thread::scope;
use std::sync::{Mutex, Arc};

fn main() {
  let data = Arc::new(Mutex::new(vec![]));  

  scope(|s| {
    for _ in 1..3 {
      s.spawn({           // 表达式块,返回闭包!
        let d = data.clone();
        move || {      
          let mut v = d.lock().unwrap();
          for i in 1..=10 {
            v.push(i);
          }
        }
      }); 
    }
  });

  println!("{:?}", data.lock().unwrap());
}
// mod util;
// use util::*;

use std::thread::{ scope, park };
use std::sync::{ RwLock, Arc };

fn main() {
  let data = Arc::new(RwLock::new(vec![]));  

  scope(|s| {

    // reader
    let t = s.spawn({
      let d = data.clone();
      move || {     
        park();  // sleep !
        let v = d.read().unwrap();
        println!("{:?}", v);
      }
    }); 

    // writer
    s.spawn({
      let d = data.clone();
      move || {      
        let mut v = d.write().unwrap();
        for i in 1..=10 {
          v.push(i);
        }

        t.thread().unpark();  // weakup!
      }
    });
  });
}

标记

两个相关特征,标记(marker)类型是否线程安全(thread safely)。

  • Send :跨线程传递(move)安全。
  • Sync :多线程共享(&T)安全。
impl<T> Send for Arc<T>
impl<T> Sync for Arc<T>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文