forked from rayon-rs/rayon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Guard
par_bridge
against work-stealing recursion
It doesn't make sense for the `par_bridge` producer to run nested on one thread, since each split is capable of running the entire iterator to completion. However, this can still happen if the serial iterator or the consumer side make any rayon calls that would block, where it may go into work-stealing and start another split of the `par_bridge`. With the iterator in particular, this is a problem because we'll already be holding the mutex, so trying to lock again will deadlock or panic. We now set a flag in each thread when they start working on the bridge, and bail out if we re-enter that bridge again on the same thread. The new `par_bridge_recursion` test would previously hang almost every time for me, but runs reliably with this new check in place.
- Loading branch information
Showing
2 changed files
with
63 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use rayon::prelude::*; | ||
use std::iter::once_with; | ||
|
||
const N: usize = 100_000; | ||
|
||
#[test] | ||
fn par_bridge_recursion() { | ||
let pool = rayon::ThreadPoolBuilder::new() | ||
.num_threads(10) | ||
.build() | ||
.unwrap(); | ||
|
||
let seq: Vec<_> = (0..N).map(|i| (i, i.to_string())).collect(); | ||
|
||
pool.broadcast(|_| { | ||
let mut par: Vec<_> = (0..N) | ||
.into_par_iter() | ||
.flat_map(|i| { | ||
once_with(move || { | ||
// Using rayon within the serial iterator creates an opportunity for | ||
// work-stealing to make par_bridge's mutex accidentally recursive. | ||
rayon::join(move || i, move || i.to_string()) | ||
}) | ||
.par_bridge() | ||
}) | ||
.collect(); | ||
par.par_sort_unstable(); | ||
assert_eq!(seq, par); | ||
}); | ||
} |