Come faccio a passare fette disgiunte da un vettore a thread diversi?

Sono nuovo di Rust e sto lottando per affrontare tutti quei tipi di wrapper in Rust. Sto cercando di scrivere un codice semanticamente uguale al seguente codice C. Il codice tenta di creare una grande tabella per la conservazione dei libri, ma dividerà la tabella grande in modo che ogni thread acceda solo alle piccole sezioni locali di tale tabella. La grande tabella non sarà accessibile a meno che altri thread non si chiudano e non accedano più alla propria sezione.

#include  #include  void* write_slice(void* arg) { int* slice = (int*) arg; int i; for (i = 0; i < 10; i++) slice[i] = i; return NULL; } int main() { int* table = (int*) malloc(100 * sizeof(int)); int* slice[10]; int i; for (i = 0; i < 10; i++) { slice[i] = table + i * 10; } // create pthread for each slice pthread_t p[10]; for (i = 0; i < 10; i++) pthread_create(&p[i], NULL, write_slice, slice[i]); for (i = 0; i < 10; i++) pthread_join(p[i], NULL); for (i = 0; i < 100; i++) printf("%d,", table[i]); } 

Come utilizzo i tipi e la proprietà di Rust per raggiungere questo objective?

Iniziamo con il codice:

 // cargo-deps: crossbeam="0.1.6" extern crate crossbeam; const CHUNKS: usize = 10; const CHUNK_SIZE: usize = 10; fn main() { let mut table = [0; CHUNKS * CHUNK_SIZE]; // Scoped threads allow the compiler to prove that no threads will outlive // table (which would be bad). crossbeam::scope(|scope| { // Chop `table` into disjoint sub-slices. for slice in table.chunks_mut(CHUNK_SIZE) { // Spawn a thread operating on that subslice. scope.spawn(move || write_slice(slice)); } // `crossbeam::scope` ensures that *all* spawned threads join before // returning control back from this closure. }); // At this point, all threads have joined, and we have exclusive access to // `table` again. Huzzah for 100% safe multi-threaded stack mutation! println!("{:?}", &table[..]); } fn write_slice(slice: &mut [i32]) { for (i, e) in slice.iter_mut().enumerate() { *e = i as i32; } } 

Una cosa da notare è che questo ha bisogno della cassa crossbeam . Rust aveva un simile costrutto “scoped”, ma un foro di solidità è stato trovato poco prima della 1.0, quindi è stato deprecato senza alcun tempo per sostituirlo. crossbeam è fondamentalmente la sostituzione.

Ciò che Rust ti consente di fare qui è esprimere l’idea che, qualunque sia il codice, nessuno dei thread creati all’interno della chiamata a crossbeam::scoped sopravviverà a tale ambito. In quanto tale, qualsiasi cosa presa in prestito da questo ambito vivrà più a lungo dei thread. In questo modo, i thread possono accedere liberamente a quelle prese in prestito senza doversi preoccupare di cose come, ad esempio, un thread che sopravvive sul frame dello stack definito da tale table e che scarabocchia oltre lo stack.

Quindi questo dovrebbe fare più o meno la stessa cosa del codice C, anche se senza quella fastidiosa preoccupazione che potresti aver perso qualcosa. 🙂

Infine, ecco la stessa cosa usando scoped_threadpool . L’unica vera differenza pratica è che questo ci consente di controllare il numero di thread utilizzati.

 // cargo-deps: scoped_threadpool="0.1.6" extern crate scoped_threadpool; const CHUNKS: usize = 10; const CHUNK_SIZE: usize = 10; fn main() { let mut table = [0; CHUNKS * CHUNK_SIZE]; let mut pool = scoped_threadpool::Pool::new(CHUNKS as u32); pool.scoped(|scope| { for slice in table.chunks_mut(CHUNK_SIZE) { scope.execute(move || write_slice(slice)); } }); println!("{:?}", &table[..]); } fn write_slice(slice: &mut [i32]) { for (i, e) in slice.iter_mut().enumerate() { *e = i as i32; } }