rollup merge of #24385: aturon/unstable-scoped
Conflicts: src/libstd/thread/mod.rs src/test/bench/shootout-mandelbrot.rs src/test/bench/shootout-reverse-complement.rs src/test/run-pass/capturing-logging.rs src/test/run-pass/issue-9396.rs src/test/run-pass/tcp-accept-stress.rs src/test/run-pass/tcp-connect-timeouts.rs src/test/run-pass/tempfile.rs
This commit is contained in:
@@ -67,15 +67,35 @@
|
||||
//! thread. This means that it can outlive its parent (the thread that spawned
|
||||
//! it), unless this parent is the main thread.
|
||||
//!
|
||||
//! ## Scoped threads
|
||||
//!
|
||||
//! Often a parent thread uses a child thread to perform some particular task,
|
||||
//! and at some point must wait for the child to complete before continuing.
|
||||
//! For this scenario, use the `thread::scoped` function:
|
||||
//! The parent thread can also wait on the completion of the child
|
||||
//! thread; a call to `spawn` produces a `JoinHandle`, which provides
|
||||
//! a `join` method for waiting:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! let child = thread::spawn(move || {
|
||||
//! // some work here
|
||||
//! });
|
||||
//! // some work here
|
||||
//! let res = child.join();
|
||||
//! ```
|
||||
//!
|
||||
//! The `join` method returns a `Result` containing `Ok` of the final
|
||||
//! value produced by the child thread, or `Err` of the value given to
|
||||
//! a call to `panic!` if the child panicked.
|
||||
//!
|
||||
//! ## Scoped threads
|
||||
//!
|
||||
//! The `spawn` method does not allow the child and parent threads to
|
||||
//! share any stack data, since that is not safe in general. However,
|
||||
//! `scoped` makes it possible to share the parent's stack by forcing
|
||||
//! a join before any relevant stack frames are popped:
|
||||
//!
|
||||
//! ```rust
|
||||
//! # #![feature(scoped)]
|
||||
//! use std::thread;
|
||||
//!
|
||||
//! let guard = thread::scoped(move || {
|
||||
//! // some work here
|
||||
//! });
|
||||
@@ -253,8 +273,8 @@ impl Builder {
|
||||
/// `io::Result` to capture any failure to create the thread at
|
||||
/// the OS level.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn spawn<F>(self, f: F) -> io::Result<JoinHandle> where
|
||||
F: FnOnce(), F: Send + 'static
|
||||
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
|
||||
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
|
||||
{
|
||||
self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i))
|
||||
}
|
||||
@@ -274,7 +294,8 @@ impl Builder {
|
||||
/// Unlike the `scoped` free function, this method yields an
|
||||
/// `io::Result` to capture any failure to create the thread at
|
||||
/// the OS level.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[unstable(feature = "scoped",
|
||||
reason = "memory unsafe if destructor is avoided, see #24292")]
|
||||
pub fn scoped<'a, T, F>(self, f: F) -> io::Result<JoinGuard<'a, T>> where
|
||||
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
|
||||
{
|
||||
@@ -370,7 +391,9 @@ impl Builder {
|
||||
/// Panics if the OS fails to create a thread; use `Builder::spawn`
|
||||
/// to recover from such errors.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
|
||||
pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
|
||||
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
|
||||
{
|
||||
Builder::new().spawn(f).unwrap()
|
||||
}
|
||||
|
||||
@@ -387,7 +410,8 @@ pub fn spawn<F>(f: F) -> JoinHandle where F: FnOnce(), F: Send + 'static {
|
||||
///
|
||||
/// Panics if the OS fails to create a thread; use `Builder::scoped`
|
||||
/// to recover from such errors.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[unstable(feature = "scoped",
|
||||
reason = "memory unsafe if destructor is avoided, see #24292")]
|
||||
pub fn scoped<'a, T, F>(f: F) -> JoinGuard<'a, T> where
|
||||
T: Send + 'a, F: FnOnce() -> T, F: Send + 'a
|
||||
{
|
||||
@@ -635,9 +659,9 @@ impl<T> JoinInner<T> {
|
||||
/// handle: the ability to join a child thread is a uniquely-owned
|
||||
/// permission.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct JoinHandle(JoinInner<()>);
|
||||
pub struct JoinHandle<T>(JoinInner<T>);
|
||||
|
||||
impl JoinHandle {
|
||||
impl<T> JoinHandle<T> {
|
||||
/// Extracts a handle to the underlying thread
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn thread(&self) -> &Thread {
|
||||
@@ -649,13 +673,14 @@ impl JoinHandle {
|
||||
/// If the child thread panics, `Err` is returned with the parameter given
|
||||
/// to `panic`.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn join(mut self) -> Result<()> {
|
||||
pub fn join(mut self) -> Result<T> {
|
||||
self.0.join()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Drop for JoinHandle {
|
||||
#[unsafe_destructor]
|
||||
impl<T> Drop for JoinHandle<T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.joined {
|
||||
unsafe { imp::detach(self.0.native) }
|
||||
@@ -674,7 +699,8 @@ impl Drop for JoinHandle {
|
||||
/// handle: the ability to join a child thread is a uniquely-owned
|
||||
/// permission.
|
||||
#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[unstable(feature = "scoped",
|
||||
reason = "memory unsafe if destructor is avoided, see #24292")]
|
||||
pub struct JoinGuard<'a, T: Send + 'a> {
|
||||
inner: JoinInner<T>,
|
||||
_marker: PhantomData<&'a T>,
|
||||
@@ -706,7 +732,8 @@ impl<'a, T: Send + 'a> JoinGuard<'a, T> {
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[unstable(feature = "scoped",
|
||||
reason = "memory unsafe if destructor is avoided, see #24292")]
|
||||
impl<'a, T: Send + 'a> Drop for JoinGuard<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
if !self.inner.joined {
|
||||
|
||||
Reference in New Issue
Block a user