返回

Rust 中 Arc 和 Mutex 的协同作用

后端

在 Rust 中,多线程编程需要解决并发访问共享内存问题。Arc 和 Mutex 是两种重要的并发原语,共同协作,确保线程安全和数据完整性。

Arc:原子引用计数

Arc(原子引用计数)是一种智能指针,允许多个线程同时持有对共享数据的引用。它使用原子引用计数器,记录指向数据的指针数量。当引用计数器变为 0 时,数据将被释放。

Mutex:互斥锁

Mutex(互斥锁)是一种同步原语,用于保护共享数据,防止多个线程同时对其进行修改。它提供了一个锁定/解锁机制,一次只允许一个线程访问共享数据。

协同作用:保护共享可变数据

Arc 和 Mutex 通常一起使用,以保护共享的可变数据。Arc 允许多个线程同时访问数据,而 Mutex 则确保一次只有一个线程可以修改数据。

这种协作方式可以防止数据竞态,即多个线程同时修改共享数据,导致不确定的结果。例如:

// 使用 Arc 共享可变数据
let shared_data = Arc::new(Mutex::new(0));

// 创建多个线程,每个线程都尝试修改共享数据
let threads = (0..10).map(|_| {
    let shared_data = shared_data.clone();
    thread::spawn(move || {
        // 获取互斥锁
        let mut data = shared_data.lock().unwrap();
        // 修改共享数据
        *data += 1;
        // 释放互斥锁
        drop(data);
    })
});

// 等待所有线程完成
for thread in threads {
    thread.join().unwrap();
}

// 检查共享数据是否被正确修改
assert_eq!(*shared_data.lock().unwrap(), 10);

Mutex 的独立使用:保护只读数据

尽管 Arc 和 Mutex 通常一起使用,但 Mutex 也可以独立使用,以保护只读数据。在这种情况下,不需要使用 Arc,因为只有一个线程可以访问数据。例如:

// 使用 Mutex 保护只读数据
let shared_data = Mutex::new(0);

// 创建多个线程,每个线程都尝试读取共享数据
let threads = (0..10).map(|_| {
    let shared_data = shared_data.clone();
    thread::spawn(move || {
        // 获取互斥锁
        let data = shared_data.lock().unwrap();
        // 读取共享数据
        println!("{}", *data);
        // 释放互斥锁
        drop(data);
    })
});

// 等待所有线程完成
for thread in threads {
    thread.join().unwrap();
}

总结

Arc 和 Mutex 在 Rust 中并发编程中扮演着至关重要的角色。Arc 允许多个线程同时访问共享数据,而 Mutex 则确保一次只有一个线程可以修改数据。通过协同作用,它们为共享可变数据提供了安全且高效的访问方式。此外,Mutex 还可以独立使用,以保护只读数据。