-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
std::thread::scope()
improvements
#98517
Conversation
kprotty
commented
Jun 26, 2022
- avoids calling to Thread::unpark() opportunistically.
- avoids calling thread::current() opportunistically.
- properly pins ScopeData to indicate its on-stack nature.
- outlines fast and slow paths for inc/dec/wait.
- specializes on ThreadSanitizer for fences.
- uses atomic intrinsics to avoid dangling shared references.
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @m-ou-se (or someone else) soon. Please see the contribution instructions for more information. |
std::thread::scope()
improvements
What's the point of using |
This adds a lot of complexity, with no clear benefit. Do you have any benchmark or real-world use case where this matters? |
library/std/src/thread/scoped.rs
Outdated
main_thread: Cell<Option<Thread>>, | ||
_pinned: PhantomPinned, | ||
} | ||
|
||
unsafe impl Send for ScopeData {} | ||
unsafe impl Sync for ScopeData {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using Cell
together with unsafe impl Sync
is probably a bad idea. It removes all checks: any thread can now just call .get()
and .set()
on it, without any unsafe
block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All methods that operate on it are within the impl and main_thread
cell accesses are commented as to who/when/how it's accessed. The Sync/Send
are to get it to compile with Arc'ing of Packet
internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. I'm not saying that your code is unsound. I'm saying that it's very easy to make a mistake when forcing a Cell into a Sync type. We usually avoid that and keep using UnsafeCell to make sure we have to write unsafe
when using it, so it can't accidentally be used from the wrong thread without thinking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that makes sense.
On macos, |
Slower, but probably still insignificant compared to spawning new threads, I assume? I can see how this can make a significant difference for empty scopes where no threads are spawned, but I wonder if there are any realistic cases where this change makes a difference. |
You're right, TLS access is almost always faster than spawning threads on tier-1 and tier-2 platforms. It could maybe make a difference if the spawned threads completed before the scope completes or if no threads are ever spawned as mentioned. |
This does sound like a fairly common case (IME it is for my usage of crossbeam::scope anyway).
OTOH this doesn't sound worth optimizing for. |
☔ The latest upstream changes (presumably #98730) made this pull request unmergeable. Please resolve the merge conflicts. |
- avoids calling to Thread::unpark() opportunistically. - avoids calling thread::current() opportunistically. - properly pins ScopeData to indicate its on-stack nature. - outlines fast and slow paths for inc/dec/wait. - specializes on ThreadSanitizer for fences. - uses atomic intrinsics to avoid dangling shared references.
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
The job Click to see the possible cause of the failure (guessed by this bot)
|
a_thread_panicked: AtomicBool, | ||
main_thread: Thread, | ||
sync_state: AtomicUsize, | ||
thread_panicked: AtomicBool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the previous name makes more sense. This is true when any thread panicked. thread_panicked
to me suggests that there is only a single thread.