-
Notifications
You must be signed in to change notification settings - Fork 566
Open
Labels
Description
To implement custom fork/join patterns that join and scope do not allow it would be helpful if spawn returned a join handle. Joining the join handle on a Rayon thread would continue running tasks until the task in question finishes. AFAICT implementing join handles outside of Rayon is impossible without busy looping or sleeping given the current API.
Example suboptimal implementation of join handles:
struct JoinHandle(mpsc::Receiver<()>);
fn spawn_with_join_handle<F>(func: F) -> JoinHandle
where F: 'static + FnOnce() + Send
{
let (sender, receiver) = mpsc::channel();
rayon::spawn(|| { f(); sender.send(); });
JoinHandle(receiver)
}
impl JoinHandle
{
fn join(self)
{
loop {
let result = self.0.try_recv();
if result.is_ok() {
break
} else {
let result = rayon::yield_now();
if result.is_none() {
self.0.recv();
break
}
}
}
}
}Example use case of implementing the Box2D task API (which is essentially fork–join):
unsafe extern "C" fn b2EnqueueTaskCallback(
task: b2TaskCallback,
itemCount: c_int,
minRange: c_int,
taskContext: *mut c_void,
userContext: *mut c_void,
) -> *mut c_void
{
let join_handle = rayon::spawn_broadcast(|...| task(..., taskContext));
Box::into_raw(Box::new(join_handle)).cast()
}
unsafe extern "C" fn b2FinishTaskCallback(userTask: *mut c_void, userContext: *mut c_void)
{
Box::from_raw::<rayon::JoinHandle>(userTask).join();
}