Skip to content

Commit 03578b2

Browse files
committed
Add ThreadPoolBuilder::build_scoped()
1 parent 58e109a commit 03578b2

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

rayon-core/src/lib.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ use std::str::FromStr;
3434

3535
extern crate crossbeam_deque;
3636
extern crate crossbeam_queue;
37+
extern crate crossbeam_utils;
3738
#[cfg(any(debug_assertions, rayon_unstable))]
3839
#[macro_use]
3940
extern crate lazy_static;
@@ -186,6 +187,37 @@ impl ThreadPoolBuilder {
186187
ThreadPool::build(self)
187188
}
188189

190+
/// Create a scoped `ThreadPool` initialized using this configuration.
191+
///
192+
/// The threads in this pool will start by calling `wrapper`, which should
193+
/// do initialization and continue by calling `ThreadBuilder::run()`.
194+
pub fn build_scoped<W, F, R>(self, wrapper: W, with_pool: F) -> Result<R, ThreadPoolBuildError>
195+
where
196+
W: Fn(ThreadBuilder) + Sync, // expected to call `run()`
197+
F: FnOnce(&ThreadPool) -> R,
198+
{
199+
let result = crossbeam_utils::thread::scope(|scope| {
200+
let wrapper = &wrapper;
201+
let pool = self.spawn(|thread| {
202+
let mut builder = scope.builder();
203+
if let Some(name) = thread.name() {
204+
builder = builder.name(name.to_string());
205+
}
206+
if let Some(size) = thread.stack_size() {
207+
builder = builder.stack_size(size);
208+
}
209+
builder.spawn(move |_| wrapper(thread))?;
210+
Ok(())
211+
})?;
212+
Ok(with_pool(&pool))
213+
});
214+
215+
match result {
216+
Ok(result) => result,
217+
Err(err) => unwind::resume_unwinding(err),
218+
}
219+
}
220+
189221
/// Create a new `ThreadPool` initialized using this configuration and a
190222
/// custom function for spawning threads.
191223
///

rayon-core/tests/scoped_threadpool.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct Local(i32);
1313
scoped_thread_local!(static LOCAL: Local);
1414

1515
#[test]
16-
fn scoped_tls_missing() {
16+
fn missing_scoped_tls() {
1717
LOCAL.set(&Local(42), || {
1818
let pool = ThreadPoolBuilder::new()
1919
.build()
@@ -27,7 +27,7 @@ fn scoped_tls_missing() {
2727
}
2828

2929
#[test]
30-
fn scoped_tls_threadpool() {
30+
fn spawn_scoped_tls_threadpool() {
3131
LOCAL.set(&Local(42), || {
3232
LOCAL.with(|x| {
3333
thread::scope(|scope| {
@@ -66,3 +66,36 @@ fn scoped_tls_threadpool() {
6666
});
6767
});
6868
}
69+
70+
#[test]
71+
fn build_scoped_tls_threadpool() {
72+
LOCAL.set(&Local(42), || {
73+
LOCAL.with(|x| {
74+
ThreadPoolBuilder::new()
75+
.build_scoped(
76+
move |thread| LOCAL.set(x, || thread.run()),
77+
|pool| {
78+
// The pool matches our local value.
79+
pool.install(|| {
80+
assert!(LOCAL.is_set());
81+
LOCAL.with(|y| {
82+
assert_eq!(x, y);
83+
});
84+
});
85+
86+
// If we change our local value, the pool is not affected.
87+
LOCAL.set(&Local(-1), || {
88+
pool.install(|| {
89+
assert!(LOCAL.is_set());
90+
LOCAL.with(|y| {
91+
assert_eq!(x, y);
92+
});
93+
});
94+
});
95+
},
96+
)
97+
.expect("thread pool created");
98+
// Internally, `crossbeam::scope` will wait for the threads to exit before returning.
99+
});
100+
});
101+
}

0 commit comments

Comments
 (0)