2017-04-24 15 views
0

安全Rust要求所有參考以下內容:如何告訴Rust讓我修改隱藏在RwLock後面的共享變量?

  1. 一個或多個引用(&T)的資源,
  2. 整整一個可變引用(&mut T)。

我想有一個Vec可以被多個線程讀取並且被一個寫入,但是其中只有一個應該是可能的(如語言要求)。

所以我用一個RwLock。我需要Vec<i8>。爲了讓它活得比的主要功能,我Box,然後我RwLock各地,像這樣的:

fn main() { 
    println!("Hello, world!"); 
    let mut v = vec![0, 1, 2, 3, 4, 5, 6]; 
    let val = RwLock::new(Box::new(v)); 
    for i in 0..10 { 
     thread::spawn(move || threadFunc(&val)); 
    } 
    loop { 
     let mut VecBox = (val.write().unwrap()); 
     let ref mut v1 = *(*VecBox); 
     v1.push(1); 
     //And be very busy. 
     thread::sleep(Duration::from_millis(10000)); 
    } 
} 
fn threadFunc(val: &RwLock<Box<Vec<i8>>>) { 
    loop { 
     //Use Vec 
     let VecBox = (val.read().unwrap()); 
     let ref v1 = *(*VecBox); 
     println!("{}", v1.len()); 
     //And be very busy. 
     thread::sleep(Duration::from_millis(1000)); 
    } 
} 

鏽拒絕編譯這個:

capture of moved value: `val` 
    --> src/main.rs:14:43 
     | 
    14 |   thread::spawn(move || threadFunc(&val)); 
     |      -------    ^^^ value captured here after move 
     |      | 
     |      value moved (into closure) here 

沒有螺紋:

for i in 0..10 { 
    threadFunc(&val); 
} 

它編譯。問題在於關閉。我必須「移動」它,否則Rust抱怨說它可以超過main,我也不能克隆valRwLock不執行clone())。

我該怎麼辦?

回答

2

請注意,使用RwLockMutex之間沒有結構性差異;他們只是有不同的訪問模式。相關討論見 Concurrent access to vector from multiple threads using a mutex lock

問題的核心在於您已將矢量的所有權(在RwLock中)轉讓給某個線程;因此你的主線不再已經有了。你不能訪問它,因爲它消失了。

事實上,你會遇到同樣的問題,因爲你試圖將向量傳遞給每個線程。你只有一個向量可以放棄,所以只有一個線程可以擁有它。

您需要線程安全的共享所有權,由Arc提供:

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

fn main() { 
    println!("Hello, world!"); 
    let v = vec![0, 1, 2, 3, 4, 5, 6]; 
    let val = Arc::new(RwLock::new(v)); 

    for _ in 0..10 { 
     let v = val.clone(); 
     thread::spawn(move || thread_func(v)); 
    } 

    for _ in 0..5 { 
     { 
      let mut val = val.write().unwrap(); 
      val.push(1); 
     } 
     thread::sleep(Duration::from_millis(1000)); 
    } 
} 

fn thread_func(val: Arc<RwLock<Vec<i8>>>) { 
    loop { 
     { 
      let val = val.read().unwrap(); 
      println!("{}", val.len()); 
     } 
     thread::sleep(Duration::from_millis(100)); 
    } 
} 

其他注意事項:

  1. 我刪除了無限循環中main使代碼實際上可以完成。
  2. 我修正了所有的編譯器警告。如果您要使用編譯語言,請注意警告。
    • 不必要括號
    • snake_case標識符。當然不要對局部變量使用PascalCase;這是用於類型。 camelCase不適用於Rust。
  3. 我添加了一些塊來縮短讀/寫鎖定的生存期。否則,會有很多爭用,並且子線程永遠沒有機會獲得讀鎖。
  4. let ref v1 = *(*foo);是非慣用的。首選let v1 = &**foo。根據Deref,您甚至不需要這麼做。
+0

謝謝,雖然'drop()'變量而不是黑客範圍更習慣? –

+1

@CharlesShiller請參見[有什麼選項可以在Rust中結束可變借入?](http://stackoverflow.com/q/35765440/1233251)。所以不,塊可以像你一樣習慣。 –

+0

@ E_net4在這種情況下,'drop'應該可以工作,因爲鎖看起來不像可變的借位。我不知道*這兩種*在這裏都比其他地方更習慣用法; '下降(vec)'雖然看起來很奇怪。 – Shepmaster