Rust - 跨多个线程写入向量的索引

Rust - writing to indices of a vector across multiple threads

我有一个圆形环形缓冲区(作为向量实现),我希望一个线程定期写入环形缓冲区,另一个线程定期从环形缓冲区读取。是否可以创建一个可以同时读取和写入的向量,只要访问该向量的线程不在同一索引处?

我希望达到的目标:

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

fn main() {

    let vec = Arc::new(vec![Mutex::new(1), Mutex::new(2),Mutex::new(3)]);

    {
        let vec = vec.clone();
        thread::spawn(move|| {
            let mut s2 = *vec.get_mut(2).unwrap().lock().unwrap();
            s2 = 7;
        });
    }

    println!("{}", vec[2].lock().unwrap());
}

编译器输出为:

Compiling playground v0.0.1 (/playground)
warning: variable `s2` is assigned to, but never used
  --> src/main.rs:12:21
   |
12 |             let mut s2 = *vec.get_mut(2).unwrap().lock().unwrap();
   |                     ^^
   |
   = note: `#[warn(unused_variables)]` on by default
   = note: consider using `_s2` instead

warning: value assigned to `s2` is never read
  --> src/main.rs:13:13
   |
13 |             s2 = 7;
   |             ^^
   |
   = note: `#[warn(unused_assignments)]` on by default
   = help: maybe it is overwritten before being read?

error[E0596]: cannot borrow data in an `Arc` as mutable
  --> src/main.rs:12:27
   |
12 |             let mut s2 = *vec.get_mut(2).unwrap().lock().unwrap();
   |                           ^^^ cannot borrow as mutable
   |
   = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::sync::Arc<std::vec::Vec<std::sync::Mutex<i32>>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0596`.
error: could not compile `playground`.

To learn more, run the command again with --verbose.

被试图防止竞争条件的生锈类型系统挫败:(

我不想要的

Link 去游乐场:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5b5efe91bdd45c658d11f1cefb16045e

首先,我推荐你使用std::sync::RwLock,因为它允许多个reader同时读取数据。

其次,生成线程会导致代码出现性能瓶颈。尝试使用线程池。

当然,具体的选择会根据基准测试的结果而有所不同,但这些都是一般性建议。

除了一个关键部分,你的代码大部分都是正确的。您正在使用 Mutex 实现 interior mutability 模式并提供线程安全。

内部可变性将 XOR 借用规则(N 个不可变借用或仅一个可变)的编译时检查移至 运行 时间。因此,Mutex 确保任何时候都只存在一个 reader 或只有一个作者。

当您尝试从 vec 获取可变引用时,像这样

vec.get_mut(..)

您基本上忽略了内部可变性提供的好处。编译器不能保证 XOR 规则没有被破坏,因为你借用了 vec 作为可变的。

明显的解决方案是借用 vec 作为不可变的并使用 Mutex 来防止竞争条件并且不使用编译器借用规则。

let mut s2 = vec
    .get(2) // Get immutable reference to second item
    .unwrap() // Ensure that it exists
    .lock() // Lock mutex. 
    .unwrap(); // Ensure mutex isn't poisoned.

// s2 is now `std::sync::MutexGuard<i32>`, which implements `std::ops::DerefMut`, 
// so it can get us mutable reference to data.
*s2 = 7;