Skip to content

Commit f67b81e

Browse files
committed
Stabilize std::thread
This commit takes a first pass at stabilizing `std::thread`: * It removes the `detach` method in favor of two constructors -- `spawn` for detached threads, `scoped` for "scoped" (i.e., must-join) threads. This addresses some of the surprise/frustrating debug sessions with the previous API, in which `spawn` produced a guard that on destruction joined the thread (unless `detach` was called). The reason to have the division in part is that `Send` will soon not imply `'static`, which means that `scoped` thread creation can take a closure over *shared stack data* of the parent thread. On the other hand, this means that the parent must not pop the relevant stack frames while the child thread is running. The `JoinGuard` is used to prevent this from happening by joining on drop (if you have not already explicitly `join`ed.) The APIs around `scoped` are future-proofed for the `Send` changes by taking an additional lifetime parameter. With the current definition of `Send`, this is forced to be `'static`, but when `Send` changes these APIs will gain their full flexibility immediately. Threads that are `spawn`ed, on the other hand, are detached from the start and do not yield an RAII guard. The hope is that, by making `scoped` an explicit opt-in with a very suggestive name, it will be drastically less likely to be caught by a surprising deadlock due to an implicit join at the end of a scope. * The module itself is marked stable. * Existing methods other than `spawn` and `scoped` are marked stable. The migration path is: ```rust Thread::spawn(f).detached() ``` becomes ```rust Thread::spawn(f) ``` while ```rust let res = Thread::spawn(f); res.join() ``` becomes ```rust let res = Thread::scoped(f); res.join() ``` [breaking-change]
1 parent 8efd990 commit f67b81e

File tree

1 file changed

+115
-44
lines changed

1 file changed

+115
-44
lines changed

Diff for: src/libstd/thread.rs

+115-44
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
//! each with their own stack and local state.
1717
//!
1818
//! Communication between threads can be done through
19-
//! [channels](../../std/comm/index.html), Rust's message-passing
19+
//! [channels](../../std/sync/mpsc/index.html), Rust's message-passing
2020
//! types, along with [other forms of thread
2121
//! synchronization](../../std/sync/index.html) and shared-memory data
2222
//! structures. In particular, types that are guaranteed to be
@@ -58,25 +58,45 @@
5858
//! ```rust
5959
//! use std::thread::Thread;
6060
//!
61-
//! let guard = Thread::spawn(move || {
61+
//! let thread = Thread::spawn(move || {
6262
//! println!("Hello, World!");
6363
//! // some computation here
6464
//! });
65-
//! let result = guard.join();
6665
//! ```
6766
//!
68-
//! The `spawn` function doesn't return a `Thread` directly; instead, it returns
69-
//! a *join guard* from which a `Thread` can be extracted. The join guard is an
70-
//! RAII-style guard that will automatically join the child thread (block until
71-
//! it terminates) when it is dropped. You can join the child thread in advance
72-
//! by calling the `join` method on the guard, which will also return the result
73-
//! produced by the thread.
67+
//! The spawned thread is "detached" from the current thread, meaning that it
68+
//! can outlive the thread that spawned it. (Note, however, that when the main
69+
//! thread terminates all detached threads are terminated as well.) The returned
70+
//! `Thread` handle can be used for low-level synchronization as described below.
71+
//!
72+
//! ## Scoped threads
73+
//!
74+
//! Often a parent thread uses a child thread to perform some particular task,
75+
//! and at some point must wait for the child to complete before continuing.
76+
//! For this scenario, use the `scoped` constructor:
77+
//!
78+
//! ```rust
79+
//! use std::thread::Thread;
80+
//!
81+
//! let guard = Thread::scoped(move || {
82+
//! println!("Hello, World!");
83+
//! // some computation here
84+
//! });
85+
//! // do some other work in the meantime
86+
//! let result = guard.join();
87+
//! ```
7488
//!
75-
//! If you instead wish to *detach* the child thread, allowing it to outlive its
76-
//! parent, you can use the `detach` method on the guard,
89+
//! The `scoped` function doesn't return a `Thread` directly; instead, it
90+
//! returns a *join guard* from which a `Thread` can be extracted. The join
91+
//! guard is an RAII-style guard that will automatically join the child thread
92+
//! (block until it terminates) when it is dropped. You can join the child
93+
//! thread in advance by calling the `join` method on the guard, which will also
94+
//! return the result produced by the thread. A handle to the thread itself is
95+
//! available via the `thread` method on the join guard.
7796
//!
78-
//! A handle to the thread itself is available via the `thread` method on the
79-
//! join guard.
97+
//! (Note: eventually, the `scoped` constructor will allow the parent and child
98+
//! threads to data that lives on the parent thread's stack, but some language
99+
//! changes are needed before this is possible.)
80100
//!
81101
//! ## Configuring threads
82102
//!
@@ -89,7 +109,7 @@
89109
//!
90110
//! thread::Builder::new().name("child1".to_string()).spawn(move || {
91111
//! println!("Hello, world!")
92-
//! }).detach();
112+
//! });
93113
//! ```
94114
//!
95115
//! ## Blocking support: park and unpark
@@ -124,6 +144,8 @@
124144
//!
125145
//! * It can be implemented highly efficiently on many platforms.
126146
147+
#![stable]
148+
127149
use any::Any;
128150
use boxed::Box;
129151
use cell::UnsafeCell;
@@ -144,6 +166,7 @@ use sys_common::{stack, thread_info};
144166

145167
/// Thread configuation. Provides detailed control over the properties
146168
/// and behavior of new threads.
169+
#[stable]
147170
pub struct Builder {
148171
// A name for the thread-to-be, for identification in panic messages
149172
name: Option<String>,
@@ -158,6 +181,7 @@ pub struct Builder {
158181
impl Builder {
159182
/// Generate the base configuration for spawning a thread, from which
160183
/// configuration methods can be chained.
184+
#[stable]
161185
pub fn new() -> Builder {
162186
Builder {
163187
name: None,
@@ -169,12 +193,14 @@ impl Builder {
169193

170194
/// Name the thread-to-be. Currently the name is used for identification
171195
/// only in panic messages.
196+
#[stable]
172197
pub fn name(mut self, name: String) -> Builder {
173198
self.name = Some(name);
174199
self
175200
}
176201

177202
/// Set the size of the stack for the new thread.
203+
#[stable]
178204
pub fn stack_size(mut self, size: uint) -> Builder {
179205
self.stack_size = Some(size);
180206
self
@@ -194,19 +220,41 @@ impl Builder {
194220
self
195221
}
196222

197-
/// Spawn a new joinable thread, and return a JoinGuard guard for it.
223+
/// Spawn a new detached thread, and return a handle to it.
198224
///
199225
/// See `Thead::spawn` and the module doc for more details.
200-
pub fn spawn<T, F>(self, f: F) -> JoinGuard<T> where
201-
T: Send, F: FnOnce() -> T, F: Send
202-
{
203-
self.spawn_inner(Thunk::new(f))
226+
#[unstable = "may change with specifics of new Send semantics"]
227+
pub fn spawn<F>(self, f: F) -> Thread where F: FnOnce(), F: Send + 'static {
228+
let (native, thread) = self.spawn_inner(Thunk::new(f), Thunk::with_arg(|_| {}));
229+
unsafe { imp::detach(native) };
230+
thread
204231
}
205232

206-
fn spawn_inner<T: Send>(self, f: Thunk<(), T>) -> JoinGuard<T> {
233+
/// Spawn a new child thread that must be joined within a given
234+
/// scope, and return a `JoinGuard`.
235+
///
236+
/// See `Thead::scoped` and the module doc for more details.
237+
#[unstable = "may change with specifics of new Send semantics"]
238+
pub fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T> where
239+
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
240+
{
207241
let my_packet = Packet(Arc::new(UnsafeCell::new(None)));
208242
let their_packet = Packet(my_packet.0.clone());
243+
let (native, thread) = self.spawn_inner(Thunk::new(f), Thunk::with_arg(move |: ret| unsafe {
244+
*their_packet.0.get() = Some(ret);
245+
}));
209246

247+
JoinGuard {
248+
native: native,
249+
joined: false,
250+
packet: my_packet,
251+
thread: thread,
252+
}
253+
}
254+
255+
fn spawn_inner<T: Send>(self, f: Thunk<(), T>, finish: Thunk<Result<T>, ()>)
256+
-> (imp::rust_thread, Thread)
257+
{
210258
let Builder { name, stack_size, stdout, stderr } = self;
211259

212260
let stack_size = stack_size.unwrap_or(rt::min_stack());
@@ -258,21 +306,14 @@ impl Builder {
258306
unwind::try(move || *ptr = Some(f.invoke(())))
259307
}
260308
};
261-
unsafe {
262-
*their_packet.0.get() = Some(match (output, try_result) {
263-
(Some(data), Ok(_)) => Ok(data),
264-
(None, Err(cause)) => Err(cause),
265-
_ => unreachable!()
266-
});
267-
}
309+
finish.invoke(match (output, try_result) {
310+
(Some(data), Ok(_)) => Ok(data),
311+
(None, Err(cause)) => Err(cause),
312+
_ => unreachable!()
313+
});
268314
};
269315

270-
JoinGuard {
271-
native: unsafe { imp::create(stack_size, Thunk::new(main)) },
272-
joined: false,
273-
packet: my_packet,
274-
thread: my_thread,
275-
}
316+
(unsafe { imp::create(stack_size, Thunk::new(main)) }, my_thread)
276317
}
277318
}
278319

@@ -285,11 +326,13 @@ struct Inner {
285326
unsafe impl Sync for Inner {}
286327

287328
#[derive(Clone)]
329+
#[stable]
288330
/// A handle to a thread.
289331
pub struct Thread {
290332
inner: Arc<Inner>,
291333
}
292334

335+
#[stable]
293336
unsafe impl Sync for Thread {}
294337

295338
impl Thread {
@@ -304,30 +347,47 @@ impl Thread {
304347
}
305348
}
306349

307-
/// Spawn a new joinable thread, returning a `JoinGuard` for it.
350+
/// Spawn a new detached thread, returning a handle to it.
351+
///
352+
/// The child thread may outlive the parent (unless the parent thread is the
353+
/// main thread; the whole process is terminated when the main thread
354+
/// finishes.) The thread handle can be used for low-level
355+
/// synchronization. See the module documentation for additional details.
356+
#[unstable = "may change with specifics of new Send semantics"]
357+
pub fn spawn<F>(f: F) -> Thread where F: FnOnce(), F: Send + 'static {
358+
Builder::new().spawn(f)
359+
}
360+
361+
/// Spawn a new *scoped* thread, returning a `JoinGuard` for it.
308362
///
309363
/// The join guard can be used to explicitly join the child thread (via
310364
/// `join`), returning `Result<T>`, or it will implicitly join the child
311-
/// upon being dropped. To detach the child, allowing it to outlive the
312-
/// current thread, use `detach`. See the module documentation for additional details.
313-
pub fn spawn<T, F>(f: F) -> JoinGuard<T> where
314-
T: Send, F: FnOnce() -> T, F: Send
365+
/// upon being dropped. Because the child thread may refer to data on the
366+
/// current thread's stack (hence the "scoped" name), it cannot be detached;
367+
/// it *must* be joined before the relevant stack frame is popped. See the
368+
/// module documentation for additional details.
369+
#[unstable = "may change with specifics of new Send semantics"]
370+
pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
371+
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
315372
{
316-
Builder::new().spawn(f)
373+
Builder::new().scoped(f)
317374
}
318375

319376
/// Gets a handle to the thread that invokes it.
377+
#[stable]
320378
pub fn current() -> Thread {
321379
thread_info::current_thread()
322380
}
323381

324382
/// Cooperatively give up a timeslice to the OS scheduler.
383+
#[unstable = "name may change"]
325384
pub fn yield_now() {
326385
unsafe { imp::yield_now() }
327386
}
328387

329388
/// Determines whether the current thread is panicking.
330389
#[inline]
390+
#[stable]
331391
pub fn panicking() -> bool {
332392
unwind::panicking()
333393
}
@@ -341,6 +401,7 @@ impl Thread {
341401
// future, this will be implemented in a more efficient way, perhaps along the lines of
342402
// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp
343403
// or futuxes, and in either case may allow spurious wakeups.
404+
#[unstable = "recently introduced"]
344405
pub fn park() {
345406
let thread = Thread::current();
346407
let mut guard = thread.inner.lock.lock().unwrap();
@@ -353,6 +414,7 @@ impl Thread {
353414
/// Atomically makes the handle's token available if it is not already.
354415
///
355416
/// See the module doc for more detail.
417+
#[unstable = "recently introduced"]
356418
pub fn unpark(&self) {
357419
let mut guard = self.inner.lock.lock().unwrap();
358420
if !*guard {
@@ -362,6 +424,7 @@ impl Thread {
362424
}
363425

364426
/// Get the thread's name.
427+
#[stable]
365428
pub fn name(&self) -> Option<&str> {
366429
self.inner.name.as_ref().map(|s| s.as_slice())
367430
}
@@ -375,28 +438,32 @@ impl thread_info::NewThread for Thread {
375438
/// Indicates the manner in which a thread exited.
376439
///
377440
/// A thread that completes without panicking is considered to exit successfully.
441+
#[stable]
378442
pub type Result<T> = ::result::Result<T, Box<Any + Send>>;
379443

380444
struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
381445

382446
unsafe impl<T:'static+Send> Send for Packet<T> {}
383447
unsafe impl<T> Sync for Packet<T> {}
384448

385-
#[must_use]
386449
/// An RAII-style guard that will block until thread termination when dropped.
387450
///
388451
/// The type `T` is the return type for the thread's main function.
389-
pub struct JoinGuard<T> {
452+
#[must_use]
453+
#[unstable = "may change with specifics of new Send semantics"]
454+
pub struct JoinGuard<'a, T: 'a> {
390455
native: imp::rust_thread,
391456
thread: Thread,
392457
joined: bool,
393458
packet: Packet<T>,
394459
}
395460

396-
unsafe impl<T: Send> Sync for JoinGuard<T> {}
461+
#[stable]
462+
unsafe impl<'a, T: Send + 'a> Sync for JoinGuard<'a, T> {}
397463

398-
impl<T: Send> JoinGuard<T> {
464+
impl<'a, T: Send + 'a> JoinGuard<'a, T> {
399465
/// Extract a handle to the thread this guard will join on.
466+
#[stable]
400467
pub fn thread(&self) -> &Thread {
401468
&self.thread
402469
}
@@ -406,6 +473,7 @@ impl<T: Send> JoinGuard<T> {
406473
///
407474
/// If the child thread panics, `Err` is returned with the parameter given
408475
/// to `panic`.
476+
#[stable]
409477
pub fn join(mut self) -> Result<T> {
410478
assert!(!self.joined);
411479
unsafe { imp::join(self.native) };
@@ -414,8 +482,11 @@ impl<T: Send> JoinGuard<T> {
414482
(*self.packet.0.get()).take().unwrap()
415483
}
416484
}
485+
}
417486

487+
impl<T: Send> JoinGuard<'static, T> {
418488
/// Detaches the child thread, allowing it to outlive its parent.
489+
#[experimental = "unsure whether this API imposes limitations elsewhere"]
419490
pub fn detach(mut self) {
420491
unsafe { imp::detach(self.native) };
421492
self.joined = true; // avoid joining in the destructor
@@ -424,7 +495,7 @@ impl<T: Send> JoinGuard<T> {
424495

425496
#[unsafe_destructor]
426497
#[stable]
427-
impl<T: Send> Drop for JoinGuard<T> {
498+
impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
428499
fn drop(&mut self) {
429500
if !self.joined {
430501
unsafe { imp::join(self.native) };

0 commit comments

Comments
 (0)