1

The Rayon documentation say it guarantees that using Rayon APIs will not introduce data races.

How can the compiler know that the method called by the closures is not sharing mutable state, for example RefCell<T> and Cell<T>, or using structs that are not thread-safe, for example Rc<T>?

I understand that core::marker::Sync marks types that are safe to share between threads but I don't understand how the Rayon type declarations and the compiler enforce it!

4

1 回答 1

3

You actually answered your question yourself – all closures that need to be shared between threads need to be Sync, and Rayon's API simply requires them to be Sync via trait bounds. See for example the documentation of ParallelIterator::map(), which specifies the method as

fn map<F, R>(self, map_op: F) -> Map<Self, F> where
    F: Fn(Self::Item) -> R + Sync + Send,
    R: Send, 

There isn't any deeper magic here – whenever Rayon uses a closure in a way that requires it to be Sync, e.g. by passing it on to a lower level API, Rayon restricts the corresponding parameter type with the Sync trait bound. This in turn makes sure that everything stored inside the closure is Sync, so you can't store any RefCell in the closure.

In cases like this, you can also ask the compiler for an explanation. As an example, if you try to compile this code

use std::cell::RefCell;
use rayon::prelude::*;

fn main() {
    let c = RefCell::new(5);
    let _ = [1, 2, 3]
        .par_iter()
        .map(|i| i * *c.borrow())
        .sum();
}

you will get this error (playground)

error[E0277]: `std::cell::RefCell<i32>` cannot be shared between threads safely
  --> src/main.rs:10:10
   |
10 |         .map(|i| i * *c.borrow())
   |          ^^^ `std::cell::RefCell<i32>` cannot be shared between threads safely
   |
   = help: within `[closure@src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`, the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<i32>`
   = note: required because it appears within the type `&std::cell::RefCell<i32>`
   = note: required because it appears within the type `[closure@src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`

While the compiler unfortunately does not directly mention the trait bound for the parameter of map(), it still points you to the relevant method, and explains that it expects the closure to be Sync, and the reason why it isn't.

于 2018-12-02T08:44:56.887 回答