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.
Fix TickleLatch reading stale data after set()
`TickleLatch` is used for synchronizing between multiple thread pools. It sets an internal latch, and then tries to tickle the remote pool to notice the completion. However, if the other pool is already awake and sees the set flag, it may continue and drop the whole job, invalidating further reads from the latch. We can fix this by reading all fields from the `&self` latch _before_ calling the internal `set()`. Furthermore, I've updated this to take a full `Arc<Registry>` handle, so we're also sure that the other pool won't be destroyed too soon. The new `tests/cross-pool.rs` would usually still pass before, but the race could be increased by adding a manual `yield_now()` between the `set()` and `tickle()`. This PR still passes under that same hack. Fixes rayon-rs#739.
- Loading branch information
Showing
3 changed files
with
37 additions
and
7 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
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,21 @@ | ||
use rayon::prelude::*; | ||
use rayon::ThreadPoolBuilder; | ||
|
||
#[test] | ||
fn cross_pool_busy() { | ||
let pool1 = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); | ||
let pool2 = ThreadPoolBuilder::new().num_threads(1).build().unwrap(); | ||
|
||
let n: i32 = 100; | ||
let sum: i32 = pool1.install(move || { | ||
// Each item will block on pool2, but pool1 can continue processing other work from the | ||
// parallel iterator in the meantime. There's a chance that pool1 will still be awake to | ||
// see the latch set without being tickled, and then it will drop that stack job. The latch | ||
// internals must not assume that the job will still be alive after it's set! | ||
(1..=n) | ||
.into_par_iter() | ||
.map(|i| pool2.install(move || i)) | ||
.sum() | ||
}); | ||
assert_eq!(sum, n * (n + 1) / 2); | ||
} |