Hacker News new | ask | show | jobs
by cpuguy83 1205 days ago
And all it really does is force a thread.join when "scope" goes out of scope. Maybe just me but seems only marginally useful.
5 comments

In Rust if you have a &Thing right here, you can't give that to some new thread unless you can promise the thread has a shorter lifespan than the &Thing does - otherwise the thread could access it after it ceases to exist, and you've introduced Undefined Behaviour.

Without scoped threads this means all references you want to give to a thread must be allowed to live forever, the lifetime 'static, since your threads might live forever (the mechanism to kill them could be discarded unused somehow). Since scoped threads always cease to exist when they go out of scope, we can give them references that live any time longer than that scope.

That's exactly the same as the crossbeam implementation. It's quite useful especially for relatively simple parallelism tasks.
The important part is it safely allows you to pass references or other objects with lifetimes to those threads. (Or at least lets the compiler know so you can avoid having to write unsafe things yourself.)

This happened to be useful for something I was doing at work where the wrapper for a native C library expressed the required lifetimes of the library constructs using lifetimes. (Eg. You must set up Foo before Bar, and Foo must outlive Bar. It was OK to pass Bar and use it from multiple threads, but it had a lifetime attached. Using scoped threads we can satisfy the compiler's lifetime checker, since it knows even though we gave Bar to many threads, none of them outlive Foo.)

It's a building block allowing more threading abstractions to be build on top of it without using unsafe code.

Most importantly it works with references like `&`,`&mut` or `Cow` etc.

E.g. in the example below it use used to ad-hoc implemet a typical simple parallel fold pattern where a collection of data points is chunked and split across num_cpu threads where each chunk is processed in parallel followed by combining the results.

https://play.rust-lang.org/?version=stable&mode=debug&editio...

Now in practice for many use cases you want to use more convenient/optimized libraries like rayon for this kinda of things instead of ad-hoc implementing them by hand.

But having the necessary primitives to implement it ad-hoc yourself without unsafe code is grate anyway.

Doing this using a destructor, or worse in straight-line code, turns out to be unsound. So it's more than marginally useful for those familiar with Chesterton's fence.
I didn't say it was useless, only that its use is highly limited to a very specific case, namely "do a bunch of things at the same time and block until completion".
If the scope is the lifetime of the program, then it hardly makes a difference. Note that rust programs exit upon return from main anyways.
This is the point of lifetimes. Everything has a lifetime whether or not it is annotated. Sometimes the compiler doesn't know what the lifetime of an object is, particularly in relation to other objects.

If you can scope something to main() then that is a 'static lifetime and there is no need for a scoped thread for it.