-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Mark JoinHandle with #[must_use] #48830
Conversation
An interesting comment I found in // Note that we **do not** run these tests here. The windows builders get super
// unhappy if a thread outlives the main thread and then exits at the same time
// (something deadlocks) so we just avoid this entirely by not running these
// tests.
/// ```no_run
/// use std::sync::Arc;
/// use std::thread;
///
/// let five = Arc::new(5);
///
/// for _ in 0..10 {
/// let five = Arc::clone(&five);
///
/// thread::spawn(move || {
/// println!("{:?}", five);
/// });
/// }
/// ```
|
src/libstd/thread/mod.rs
Outdated
@@ -1267,6 +1267,7 @@ impl<T> JoinInner<T> { | |||
/// [`Clone`]: ../../std/clone/trait.Clone.html | |||
/// [`thread::spawn`]: fn.spawn.html | |||
/// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn | |||
#[must_use] |
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.
It might be a good idea to add a short message, describing the reason for must_use
, like
#[must_use = "it is better to explicitly join the spawned thread, otherwise it might be terminated abruptly, without running destructors"]
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.
Done.
@@ -36,9 +36,7 @@ | |||
//! non-zero exit code. | |||
//! | |||
//! When the main thread of a Rust program terminates, the entire program shuts | |||
//! down, even if other threads are still running. However, this module provides | |||
//! convenient facilities for automatically waiting for the termination of a | |||
//! child thread (i.e., join). |
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.
Written in 2014. I wish it were still true.
Highfive failed to assign a reviewer, @Kimundi? |
I think we might want to cc @rust-lang/libs here: there will be a lot of warnings because of this, so it's better to discuss this at the team level just in case I think? |
Yeah, this seems like it might have a lot of impact. |
Thanks for the PR @stjepang! I'd personally think, however, that we would not want to do this. I think it's a laudable effort to encourage authors to think about shutdown and how to join threads, but there's a few reasons that I think we won't want to take this strategy:
I wonder though if there's perhaps another route we can take for warning about this? Not much comes to mind though :( |
I'd say the key issue here is that Maybe we don't need to "fix" let guard = thread::guarded(move || {
// ...
});
// Join the thread.
// Panics if the thread ended with a panic.
drop(guard); Also, I find the fact that the documentation says the following amusing: //! When the main thread of a Rust program terminates, the entire program shuts
//! down, even if other threads are still running. However, this module provides
//! convenient facilities for automatically waiting for the termination of a
//! child thread (i.e., join).
We're being warned than daemonized threads will not be cleanly shut down, but fret not - we're covered by convenient facilities for automatic joining. Except that's a lie - there is nothing automatic about calling |
Having an alternative seems plausible to me! |
☔ The latest upstream changes (presumably #48691) made this pull request unmergeable. Please resolve the merge conflicts. |
Where does this PR stand? Should it be closed in favor of a new API addition like the proposed |
Well, now you gotta talk about it at your meeting, so there 😝 |
Ping from triage @rust-lang/libs! What's the decision on this? |
We'll have triage this wednesday and I'll make sure we discuss it there |
We discussed this in triage and like the approach of a separate function which has a |
Isn’t |
Mostly but not entirely! In this case, code like thread::spawn_attached(|| do_expensive_work()); Is totally broken - we're presumably doing this work in a separate thread because we want to do other stuff while it's running, but the handle is going to join when it's dropped immediately. |
If I understood this correctly the PR needs to change? Marking as waiting on author @stjepang. |
Let's close this PR since it's definitely not the direction we're going to take. The alternative is to add a new function for spawning threads that returns a join-on-drop guard. |
|
This PR adds a
#[must_use]
attribute toJoinHandle
.The change may introduce a considerable number of warnings in the Rust code, but that's a good thing! Note that warnings are still easy to get around by writing
let _ = std::thread::spawn(...)
, but at least they make the user think twice about forgetting to join the thread.Generally speaking, spawning a thread with no intention of ever joining should be discouraged since it may lead to very subtle bugs. See #48820 for an explanation.
Closes #48820
cc @matklad