@@ -7,13 +7,17 @@ use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
77use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
88use crate :: sync:: { Arc , Mutex } ;
99
10- /// TODO: documentation
10+ /// A scope to spawn scoped threads in.
11+ ///
12+ /// See [`scope`] for details.
1113pub struct Scope < ' env > {
1214 data : ScopeData ,
1315 env : PhantomData < & ' env ( ) > ,
1416}
1517
16- /// TODO: documentation
18+ /// An owned permission to join on a scoped thread (block on its termination).
19+ ///
20+ /// See [`Scope::spawn`] for details.
1721pub struct ScopedJoinHandle < ' scope , T > ( JoinInner < ' scope , T > ) ;
1822
1923pub ( super ) struct ScopeData {
@@ -39,7 +43,52 @@ impl ScopeData {
3943 }
4044}
4145
42- /// TODO: documentation
46+ /// Create a scope for spawning scoped threads.
47+ ///
48+ /// The function passed to `scope` will be provided a [`Scope`] object,
49+ /// through which scoped threads can be [spawned][`Scope::spawn`].
50+ ///
51+ /// Unlike non-scoped threads, scoped threads can non-`'static` data,
52+ /// as the scope guarantees all threads will be joined at the end of the scope.
53+ ///
54+ /// All threads spawned within the scope that haven't been manually joined
55+ /// will be automatically joined before this function returns.
56+ ///
57+ /// # Panics
58+ ///
59+ /// If any of the automatically joined threads panicked, this function will panic.
60+ ///
61+ /// If you want to handle panics from spawned threads,
62+ /// [`join`][ScopedJoinHandle::join] them before the end of the scope.
63+ ///
64+ /// # Example
65+ ///
66+ /// ```
67+ /// #![feature(scoped_threads)]
68+ /// use std::thread;
69+ ///
70+ /// let mut a = vec![1, 2, 3];
71+ /// let mut x = 0;
72+ ///
73+ /// thread::scope(|s| {
74+ /// s.spawn(|_| {
75+ /// println!("hello from the first scoped thread");
76+ /// // We can borrow `a` here.
77+ /// dbg!(&a);
78+ /// });
79+ /// s.spawn(|_| {
80+ /// println!("hello from the second scoped thread");
81+ /// // We can even mutably borrow `x` here,
82+ /// // because no other threads are using it.
83+ /// x += a[0] + a[2];
84+ /// });
85+ /// println!("hello from the main thread");
86+ /// });
87+ ///
88+ /// // After the scope, we can modify and access our variables again:
89+ /// a.push(4);
90+ /// assert_eq!(x, a.len());
91+ /// ```
4392pub fn scope < ' env , F , T > ( f : F ) -> T
4493where
4594 F : FnOnce ( & Scope < ' env > ) -> T ,
@@ -80,7 +129,30 @@ where
80129}
81130
82131impl < ' env > Scope < ' env > {
83- /// TODO: documentation
132+ /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
133+ ///
134+ /// Unlike non-scoped threads, threads spawned with this function may
135+ /// borrow non-`'static` data from the outside the scope. See [`scope`] for
136+ /// details.
137+ ///
138+ /// The join handle provides a [`join`] method that can be used to join the spawned
139+ /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
140+ /// the panic payload.
141+ ///
142+ /// If the join handle is dropped, the spawned thread will implicitly joined at the
143+ /// end of the scope. In that case, if the spawned thread panics, [`scope`] will
144+ /// panic after all threads are joined.
145+ ///
146+ /// This call will create a thread using default parameters of [`Builder`].
147+ /// If you want to specify the stack size or the name of the thread, use
148+ /// [`Builder::spawn_scoped`] instead.
149+ ///
150+ /// # Panics
151+ ///
152+ /// Panics if the OS fails to create a thread; use [`Builder::spawn`]
153+ /// to recover from such errors.
154+ ///
155+ /// [`join`]: ScopedJoinHandle::join
84156 pub fn spawn < ' scope , F , T > ( & ' scope self , f : F ) -> ScopedJoinHandle < ' scope , T >
85157 where
86158 F : FnOnce ( & Scope < ' env > ) -> T + Send + ' env ,
@@ -91,7 +163,54 @@ impl<'env> Scope<'env> {
91163}
92164
93165impl Builder {
94- fn spawn_scoped < ' scope , ' env , F , T > (
166+ /// Spawns a new scoped thread using the settings set through this `Builder`.
167+ ///
168+ /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to
169+ /// capture any failure to create the thread at the OS level.
170+ ///
171+ /// [`io::Result`]: crate::io::Result
172+ ///
173+ /// # Panics
174+ ///
175+ /// Panics if a thread name was set and it contained null bytes.
176+ ///
177+ /// # Example
178+ ///
179+ /// ```
180+ /// #![feature(scoped_threads)]
181+ /// use std::thread;
182+ ///
183+ /// let mut a = vec![1, 2, 3];
184+ /// let mut x = 0;
185+ ///
186+ /// thread::scope(|s| {
187+ /// thread::Builder::new()
188+ /// .name("first".to_string())
189+ /// .spawn_scoped(s, |_|
190+ /// {
191+ /// println!("hello from the {:?} scoped thread", thread::current().name());
192+ /// // We can borrow `a` here.
193+ /// dbg!(&a);
194+ /// })
195+ /// .unwrap();
196+ /// thread::Builder::new()
197+ /// .name("second".to_string())
198+ /// .spawn_scoped(s, |_|
199+ /// {
200+ /// println!("hello from the {:?} scoped thread", thread::current().name());
201+ /// // We can even mutably borrow `x` here,
202+ /// // because no other threads are using it.
203+ /// x += a[0] + a[2];
204+ /// })
205+ /// .unwrap();
206+ /// println!("hello from the main thread");
207+ /// });
208+ ///
209+ /// // After the scope, we can modify and access our variables again:
210+ /// a.push(4);
211+ /// assert_eq!(x, a.len());
212+ /// ```
213+ pub fn spawn_scoped < ' scope , ' env , F , T > (
95214 self ,
96215 scope : & ' scope Scope < ' env > ,
97216 f : F ,
@@ -105,16 +224,61 @@ impl Builder {
105224}
106225
107226impl < ' scope , T > ScopedJoinHandle < ' scope , T > {
108- /// TODO
109- pub fn join ( self ) -> Result < T > {
110- self . 0 . join ( )
111- }
112-
113- /// TODO
227+ /// Extracts a handle to the underlying thread.
228+ ///
229+ /// # Examples
230+ ///
231+ /// ```
232+ /// #![feature(scoped_threads)]
233+ /// #![feature(thread_is_running)]
234+ ///
235+ /// use std::thread;
236+ ///
237+ /// thread::scope(|s| {
238+ /// let t = s.spawn(|_| {
239+ /// println!("hello");
240+ /// });
241+ /// println!("thread id: {:?}", t.thread().id());
242+ /// });
243+ /// ```
244+ #[ must_use]
114245 pub fn thread ( & self ) -> & Thread {
115246 & self . 0 . thread
116247 }
117248
249+ /// Waits for the associated thread to finish.
250+ ///
251+ /// This function will return immediately if the associated thread has already finished.
252+ ///
253+ /// In terms of [atomic memory orderings], the completion of the associated
254+ /// thread synchronizes with this function returning.
255+ /// In other words, all operations performed by that thread
256+ /// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses)
257+ /// all operations that happen after `join` returns.
258+ ///
259+ /// If the associated thread panics, [`Err`] is returned with the panic payload.
260+ ///
261+ /// [atomic memory orderings]: crate::sync::atomic
262+ ///
263+ /// # Examples
264+ ///
265+ /// ```
266+ /// #![feature(scoped_threads)]
267+ /// #![feature(thread_is_running)]
268+ ///
269+ /// use std::thread;
270+ ///
271+ /// thread::scope(|s| {
272+ /// let t = s.spawn(|_| {
273+ /// panic!("oh no");
274+ /// });
275+ /// assert!(t.join().is_err());
276+ /// });
277+ /// ```
278+ pub fn join ( self ) -> Result < T > {
279+ self . 0 . join ( )
280+ }
281+
118282 /// Checks if the the associated thread is still running its main function.
119283 ///
120284 /// This might return `false` for a brief moment after the thread's main
0 commit comments