How to use Boxes with rayon?

Hi !

I'm trying to use rayon with a vector of Boxed structs :

use rayon::prelude::*;

use crate::{entity::Entity, message::Message};

pub struct Orchestrator {
    entities: Vec<Box<dyn Entity>>,
}

impl Orchestrator {
    pub fn new(entities: Vec<Box<dyn Entity>>) -> Orchestrator {
        Orchestrator { entities }
    }

    pub fn operate(&self) {
        loop {
            let results: Vec<Message> = (0..self.entities.len())
                .into_par_iter()
                .flat_map(|i| self.tick_entity(i))
                .collect();
        }
    }

    fn tick_entity(&self, i: usize) -> Vec<Message> {
        vec![]
    }
}

But :

error[E0277]: `(dyn Entity + Send + 'static)` cannot be shared between threads safely
   --> src/orchestrator/mod.rs:18:18
    |
18  |                 .flat_map(|i| self.tick_entity(i))
    |                  ^^^^^^^^ `(dyn Entity + Send + 'static)` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `(dyn Entity + Send + 'static)`
    = note: required because of the requirements on the impl of `Sync` for `Unique<(dyn Entity + Send + 'static)>`
    = note: required because it appears within the type `Box<(dyn Entity + Send + 'static)>`
    = note: required because of the requirements on the impl of `Sync` for `Unique<Box<(dyn Entity + Send + 'static)>>`
    = note: required because it appears within the type `alloc::raw_vec::RawVec<Box<(dyn Entity + Send + 'static)>>`
    = note: required because it appears within the type `Vec<Box<(dyn Entity + Send + 'static)>>`
note: required because it appears within the type `Orchestrator`
   --> src/orchestrator/mod.rs:5:12
    |
5   | pub struct Orchestrator {
    |            ^^^^^^^^^^^^
    = note: required because it appears within the type `&Orchestrator`
    = note: required because it appears within the type `&&Orchestrator`
    = note: required because it appears within the type `[closure@src/orchestrator/mod.rs:18:27: 18:50]`
note: required by a bound in `rayon::iter::ParallelIterator::flat_map`
   --> /home/bastiensevajol/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.1/src/iter/mod.rs:848:35
    |
848 |         F: Fn(Self::Item) -> PI + Sync + Send,
    |                                   ^^^^ required by this bound in `rayon::iter::ParallelIterator::flat_map`

How can I use rayon::iter::ParallelIterator::flat_map ? I just need to use Box<dyn Entity> as read only. I thought that require only Send ? :thinking:

This hasn't got anything to do with the box. You probably want dyn Entity + Send + Sync in both places where you currently have plain dyn Entity. Playground.

It would require only Send, if you were consuming the Boxes, i.e. if they were moved into the iterator. But you're only borrowing them (as part of &self), i.e. you need &Box<_> to be Send; and &T is Send iff T is Sync.

1 Like

Thanks.

Sorry, I didn't understand this.

The compiler is complaining that your &Box isn't Send, ie. the reference can't be used for shared access across threads. A reference is safe to share across threads if the pointed value ensures synchronization (or is truly read-only), a property which is captured by the Sync trait. Therefore only a T: Sync type's address &T can be Send (ie. a pointer/reference to it can be transferred/copied to a different thread).

Thanks :+1: I will study that :relieved:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.