Skip to content

Commit 6e0fb70

Browse files
committed
Generalize spawn beyond unit closures
`thread::spawn` was previously restricted to closures that return `()`, which limited the utility of joining on a spawned thread. However, there is no reason for this restriction, and this commit allows arbitrary return types. Since it introduces a type parameter to `JoinHandle`, it's technically a: [breaking-change] However, no code is actually expected to break.
1 parent 6399bb4 commit 6e0fb70

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

src/libstd/thread/mod.rs

+32-10
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,30 @@
6767
//! thread. This means that it can outlive its parent (the thread that spawned
6868
//! it), unless this parent is the main thread.
6969
//!
70+
//! The parent thread can also wait on the completion of the child
71+
//! thread; a call to `spawn` produces a `JoinHandle`, which provides
72+
//! a `join` method for waiting:
73+
//!
74+
//! ```rust
75+
//! use std::thread;
76+
//!
77+
//! let child = thread::spawn(move || {
78+
//! // some work here
79+
//! });
80+
//! // some work here
81+
//! let res = child.join();
82+
//! ```
83+
//!
84+
//! The `join` method returns a `Result` containing `Ok` of the final
85+
//! value produced by the child thread, or `Err` of the value given to
86+
//! a call to `panic!` if the child panicked.
87+
//!
7088
//! ## Scoped threads
7189
//!
72-
//! Often a parent thread uses a child thread to perform some particular task,
73-
//! and at some point must wait for the child to complete before continuing.
74-
//! For this scenario, use the `thread::scoped` function:
90+
//! The `spawn` method does not allow the child and parent threads to
91+
//! share any stack data, since that is not safe in general. However,
92+
//! `scoped` makes it possible to share the parent's stack by forcing
93+
//! a join before any relevant stack frames are popped:
7594
//!
7695
//! ```rust
7796
//! use std::thread;
@@ -253,8 +272,8 @@ impl Builder {
253272
/// `io::Result` to capture any failure to create the thread at
254273
/// the OS level.
255274
#[stable(feature = "rust1", since = "1.0.0")]
256-
pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
257-
F: FnOnce(), F: Send + 'static
275+
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
276+
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
258277
{
259278
self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i))
260279
}
@@ -371,7 +390,9 @@ impl Builder {
371390
/// Panics if the OS fails to create a thread; use `Builder::spawn`
372391
/// to recover from such errors.
373392
#[stable(feature = "rust1", since = "1.0.0")]
374-
pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
393+
pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
394+
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
395+
{
375396
Builder::new().spawn(f).unwrap()
376397
}
377398

@@ -637,9 +658,9 @@ impl<T> JoinInner<T> {
637658
/// handle: the ability to join a child thread is a uniquely-owned
638659
/// permission.
639660
#[stable(feature = "rust1", since = "1.0.0")]
640-
pub struct JoinHandle(JoinInner<()>);
661+
pub struct JoinHandle<T>(JoinInner<T>);
641662

642-
impl JoinHandle {
663+
impl<T> JoinHandle<T> {
643664
/// Extract a handle to the underlying thread
644665
#[stable(feature = "rust1", since = "1.0.0")]
645666
pub fn thread(&self) -> &Thread {
@@ -651,13 +672,14 @@ impl JoinHandle {
651672
/// If the child thread panics, `Err` is returned with the parameter given
652673
/// to `panic`.
653674
#[stable(feature = "rust1", since = "1.0.0")]
654-
pub fn join(mut self) -> Result<()> {
675+
pub fn join(mut self) -> Result<T> {
655676
self.0.join()
656677
}
657678
}
658679

659680
#[stable(feature = "rust1", since = "1.0.0")]
660-
impl Drop for JoinHandle {
681+
#[unsafe_destructor]
682+
impl<T> Drop for JoinHandle<T> {
661683
fn drop(&mut self) {
662684
if !self.0.joined {
663685
unsafe { imp::detach(self.0.native) }

0 commit comments

Comments
 (0)