@@ -7,13 +7,17 @@ use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
7
7
use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
8
8
use crate :: sync:: { Arc , Mutex } ;
9
9
10
- /// TODO: documentation
10
+ /// A scope to spawn scoped threads in.
11
+ ///
12
+ /// See [`scope`] for details.
11
13
pub struct Scope < ' env > {
12
14
data : ScopeData ,
13
15
env : PhantomData < & ' env ( ) > ,
14
16
}
15
17
16
- /// TODO: documentation
18
+ /// An owned permission to join on a scoped thread (block on its termination).
19
+ ///
20
+ /// See [`Scope::spawn`] for details.
17
21
pub struct ScopedJoinHandle < ' scope , T > ( JoinInner < ' scope , T > ) ;
18
22
19
23
pub ( super ) struct ScopeData {
@@ -39,7 +43,52 @@ impl ScopeData {
39
43
}
40
44
}
41
45
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
+ /// ```
43
92
pub fn scope < ' env , F , T > ( f : F ) -> T
44
93
where
45
94
F : FnOnce ( & Scope < ' env > ) -> T ,
@@ -80,7 +129,30 @@ where
80
129
}
81
130
82
131
impl < ' 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
84
156
pub fn spawn < ' scope , F , T > ( & ' scope self , f : F ) -> ScopedJoinHandle < ' scope , T >
85
157
where
86
158
F : FnOnce ( & Scope < ' env > ) -> T + Send + ' env ,
@@ -91,7 +163,54 @@ impl<'env> Scope<'env> {
91
163
}
92
164
93
165
impl 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 > (
95
214
self ,
96
215
scope : & ' scope Scope < ' env > ,
97
216
f : F ,
@@ -105,16 +224,61 @@ impl Builder {
105
224
}
106
225
107
226
impl < ' 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]
114
245
pub fn thread ( & self ) -> & Thread {
115
246
& self . 0 . thread
116
247
}
117
248
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
+
118
282
/// Checks if the the associated thread is still running its main function.
119
283
///
120
284
/// This might return `false` for a brief moment after the thread's main
0 commit comments