2015-03-08 5 views
6

Czy ktoś mógłby wyjaśnić, dlaczego poniższy kod nie działa równolegle? Chyba nie rozumiem, jak thread::scoped prace ..Kod nie działa równolegle podczas używania wątku :: scoped

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

fn main() { 
    let buf = Arc::new(Mutex::new(Vec::<String>::new())); 
    let res = test(buf); 
    println!("{:?}", *res.lock().unwrap()); 
} 

fn test(buf: Arc<Mutex<Vec<String>>>) -> Arc<Mutex<Vec<String>>> { 
    let guards: Vec<_> = (0..3).map(|i| { 
     let mtx = buf.clone(); 
     thread::scoped(|| { 
      println!("Thread: {}", i); 
      let mut res = mtx.lock().unwrap(); 
      timer::sleep(Duration::seconds(5)); 
      res.push(format!("thread {}", i)); 
     }); 
    }).collect(); 
    buf 
} 

Kod jest oparty na przykładach here gdzie stwierdził:

scoped funkcja przyjmuje jeden argument, zamknięcie, wskazaną przez podwójne paski ||. To zamknięcie jest wykonywane w nowym wątku utworzonym przez zakres. Ta metoda nazywa się scoped, ponieważ zwraca 'join guard', która automatycznie dołącza do wątku podrzędnego, gdy wykracza poza zakres. Ponieważ zbieramy tych strażników do Vec, a ten wektor wykracza poza zakres naszego programu, nasz program będzie czekał na zakończenie każdego wątku.

Dzięki

+2

mam składać [PR] (https://github.com/rust-lang/rust/pull/23202) naprawić oryginalne dokumenty. – Shepmaster

Odpowiedz

10

Jest to trudne przypadek. Problemem jest skromny średnik. Spójrz na ten kod zminimalizowanym:

thread::scoped(|| {}); 

To oznacza, że ​​średnik wynik collectnie jest wektorem JoinGuard s - to Vec<()>! Każdy JoinGuard jest natychmiast upuszczany, zmuszając koniec nici do rozpoczęcia kolejnej iteracji.

Po rozwiązaniu tego problemu, pojawi się następny problem, który oznacza, że ​​i i mtx nie żyją wystarczająco długo. Musisz move je do zamknięcia:

thread::scoped(move || {}) 
+1

Wygląda na to, że 'JoinGuard' jest kandydatem do' # [must_use] 'mabye? – sellibitze

+0

@sellibitze z pewnością wydaje się, że to może być dobra okazja! Jaki jest odpowiedni proces? – Shepmaster

+0

Spróbuj przesłać go do rdzenia programistów w '# rust-internals' i zobaczyć, co się dzieje, jak sądzę. :) – sellibitze