-
Notifications
You must be signed in to change notification settings - Fork 542
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();
}