diff options
| author | Konrad Borowski <konrad@borowski.pw> | 2018-12-23 16:47:11 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-12-23 16:47:11 +0100 |
| commit | 8ac5380ea0204dbdcbc8108d259928b67d5f8ebb (patch) | |
| tree | 174d912756fc2678af50d46ff457f7504750a975 /src/libstd/thread | |
| parent | b4a306c1e648c84f289c63e984941b7faad10af1 (diff) | |
| parent | ddab10a692aab2e2984b5c826ed9d78a57e94851 (diff) | |
| download | rust-8ac5380ea0204dbdcbc8108d259928b67d5f8ebb.tar.gz rust-8ac5380ea0204dbdcbc8108d259928b67d5f8ebb.zip | |
Merge branch 'master' into copied
Diffstat (limited to 'src/libstd/thread')
| -rw-r--r-- | src/libstd/thread/local.rs | 2 | ||||
| -rw-r--r-- | src/libstd/thread/mod.rs | 59 |
2 files changed, 47 insertions, 14 deletions
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 4df47511172..8bb99096061 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -269,7 +269,7 @@ impl<T: 'static> LocalKey<T> { // ptr::write(ptr, Some(value)) // // Due to this pattern it's possible for the destructor of the value in - // `ptr` (e.g. if this is being recursively initialized) to re-access + // `ptr` (e.g., if this is being recursively initialized) to re-access // TLS, in which case there will be a `&` and `&mut` pointer to the same // value (an aliasing violation). To avoid setting the "I'm running a // destructor" flag we just use `mem::replace` which should sequence the diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 3a9f3ec5c6f..b70dfc46af5 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -93,7 +93,7 @@ //! Threads are represented via the [`Thread`] type, which you can get in one of //! two ways: //! -//! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] +//! * By spawning a new thread, e.g., using the [`thread::spawn`][`spawn`] //! function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`]. //! * By requesting the current thread, using the [`thread::current`] function. //! @@ -124,7 +124,7 @@ //! thread, use [`Thread::name`]. A couple examples of where the name of a thread gets used: //! //! * If a panic occurs in a named thread, the thread name will be printed in the panic message. -//! * The thread name is provided to the OS where applicable (e.g. `pthread_setname_np` in +//! * The thread name is provided to the OS where applicable (e.g., `pthread_setname_np` in //! unix-like platforms). //! //! ## Stack size @@ -167,10 +167,12 @@ #![stable(feature = "rust1", since = "1.0.0")] use any::Any; +use boxed::FnBox; use cell::UnsafeCell; use ffi::{CStr, CString}; use fmt; use io; +use mem; use panic; use panicking; use str; @@ -420,7 +422,7 @@ impl Builder { /// /// - ensure that [`join`][`JoinHandle::join`] is called before any referenced /// data is dropped - /// - use only types with `'static` lifetime bounds, i.e. those with no or only + /// - use only types with `'static` lifetime bounds, i.e., those with no or only /// `'static` references (both [`thread::Builder::spawn`][`Builder::spawn`] /// and [`thread::spawn`][`spawn`] enforce this property statically) /// @@ -452,8 +454,8 @@ impl Builder { /// [`io::Result`]: ../../std/io/type.Result.html /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html #[unstable(feature = "thread_spawn_unchecked", issue = "55132")] - pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where - F: FnOnce() -> T, F: Send, T: Send + pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>> where + F: FnOnce() -> T, F: Send + 'a, T: Send + 'a { let Builder { name, stack_size } = self; @@ -482,7 +484,21 @@ impl Builder { }; Ok(JoinHandle(JoinInner { - native: Some(imp::Thread::new(stack_size, Box::new(main))?), + // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed + // through FFI or otherwise used with low-level threading primitives that have no + // notion of or way to enforce lifetimes. + // + // As mentioned in the `Safety` section of this function's documentation, the caller of + // this function needs to guarantee that the passed-in lifetime is sufficiently long + // for the lifetime of the thread. + // + // Similarly, the `sys` implementation must guarantee that no references to the closure + // exist after the thread has terminated, which is signaled by `Thread::join` + // returning. + native: Some(imp::Thread::new( + stack_size, + mem::transmute::<Box<dyn FnBox() + 'a>, Box<dyn FnBox() + 'static>>(Box::new(main)) + )?), thread: my_thread, packet: Packet(my_packet), })) @@ -676,7 +692,7 @@ pub fn yield_now() { /// already poison themselves when a thread panics while holding the lock. /// /// This can also be used in multithreaded applications, in order to send a -/// message to other threads warning that a thread has panicked (e.g. for +/// message to other threads warning that a thread has panicked (e.g., for /// monitoring purposes). /// /// # Examples @@ -806,9 +822,14 @@ const NOTIFIED: usize = 2; /// In other words, each [`Thread`] acts a bit like a spinlock that can be /// locked and unlocked using `park` and `unpark`. /// +/// Notice that being unblocked does not imply any synchronization with someone +/// that unparked this thread, it could also be spurious. +/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and +/// [`unpark`] return immediately without doing anything. +/// /// The API is typically used by acquiring a handle to the current thread, /// placing that handle in a shared data structure so that other threads can -/// find it, and then `park`ing. When some desired condition is met, another +/// find it, and then `park`ing in a loop. When some desired condition is met, another /// thread calls [`unpark`] on the handle. /// /// The motivation for this design is twofold: @@ -823,21 +844,33 @@ const NOTIFIED: usize = 2; /// /// ``` /// use std::thread; +/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}}; /// use std::time::Duration; /// -/// let parked_thread = thread::Builder::new() -/// .spawn(|| { +/// let flag = Arc::new(AtomicBool::new(false)); +/// let flag2 = Arc::clone(&flag); +/// +/// let parked_thread = thread::spawn(move || { +/// // We want to wait until the flag is set. We *could* just spin, but using +/// // park/unpark is more efficient. +/// while !flag2.load(Ordering::Acquire) { /// println!("Parking thread"); /// thread::park(); +/// // We *could* get here spuriously, i.e., way before the 10ms below are over! +/// // But that is no problem, we are in a loop until the flag is set anyway. /// println!("Thread unparked"); -/// }) -/// .unwrap(); +/// } +/// println!("Flag received"); +/// }); /// /// // Let some time pass for the thread to be spawned. /// thread::sleep(Duration::from_millis(10)); /// +/// // Set the flag, and let the thread wake up. /// // There is no race condition here, if `unpark` /// // happens first, `park` will return immediately. +/// // Hence there is no risk of a deadlock. +/// flag.store(true, Ordering::Release); /// println!("Unpark the thread"); /// parked_thread.thread().unpark(); /// @@ -1062,7 +1095,7 @@ struct Inner { /// Threads are represented via the `Thread` type, which you can get in one of /// two ways: /// -/// * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`] +/// * By spawning a new thread, e.g., using the [`thread::spawn`][`spawn`] /// function, and calling [`thread`][`JoinHandle::thread`] on the /// [`JoinHandle`]. /// * By requesting the current thread, using the [`thread::current`] function. |
