4 ms·
Once std::thread::scope[1] is stabilised, in a lot of cases you're not going to need to wrap your Mutexes in Arcs anymore: #![feature(scoped_threads)] use
by yakubin 4y ago
Once std::thread::scope[1] is stabilised, in a lot of cases you're not going to need to wrap your Mutexes in Arcs anymore:
#![feature(scoped_threads)]
use std::thread;
use std::sync::Mutex;
fn main() {
let a = Mutex::new(0u32);
thread::scope(|s| {
s.spawn(|| {
*a.lock().unwrap() += 1;
});
s.spawn(|| {
*a.lock().unwrap() += 1;
});
});
assert_eq!(*a.lock().unwrap(), 2);
}
A nice glimpse of structured concurrency.
[1]: <https://doc.rust-lang.org/std/thread/fn.scope.html https://doc.rust-lang.org/std/thread/fn.scope.html>
Edit: removed unnecessary "mut" from declaration of "a".
- drogus 4y agoIt will get even simpler when 1.63 hits with the `static` `Mutex::new`: use std::{sync::Mutex, thread, thread::sleep, time::Duration}; fn main() { static MUTEX: Mutex<String> = Mutex::new(String::new()); let t1 = thread::spawn(|| { MUTEX.lock().unwrap().push_str("hello "); }); let t2 = thread::spawn(|| { sleep(Duration::from_millis(10)); MUTEX.lock().unwrap().push_str("world!"); }); t1.join().unwrap(); t2.join().unwrap(); println!("{}", MUTEX.lock().unwrap()); } Of course you can't really use it for everything (ie. whatever you put inside `Mutex::new()` needs to be static as well, but still, it's a nice option too
- dthul 4y agoThat's a great point! If you can guarantee that the threads don't outlive the Mutex an Arc is not even necessary.
- thedracle 4y agoThis is so beautiful. Super cool not having manual thread joining code.
- bluejekyll 4y agoWoh, I missed this (from that issue thread), "Merged and stabilized in 1.63!" Scoped threads are such a brilliant thing in the context of lifetimes.
- klabb3 4y agoIt's only lexically scoped though, so you don't have much use of them in thread pools and, importantly, async runtimes. Pre-1.0, we used to have JoinHandle<'a> which let you use the borrow checker to its full potential with multiple threads. This is a big practical hurdle today, where mutices are required even for simple cases which don't suffer data races in practice.
- verdagon 4y agoVery cool! I assume that anything captured will still need to have Sync/Send?
- yakubin 4y agoYes. The reason why currently you need to wrap Mutexes in Arcs is not thread-safety per se. Without std::thread::scope the Rust compiler doesn't know if the spawned threads won't outlive the Mutex (which is borrowed by the closures). So it's more about memory-safety than thread-safety in this case. std::thread::scope guarantees that the threads will be joined in the std::thread::scope, thus providing enough information to the compiler (via lifetime annotations) for it to decide that they won't outlive the Mutex, so borrowing is safe in this case. That sorted, Mutex always had Sync and Send, so everything is in place to use it from multiple threads.