#[SOLVED] borrowed data escapes outside of method error when parallelizing functions

6 messages · Page 1 of 1 (latest)

graceful pine
#

I'm making a parallel ECS, and I'm building the scheduler for running the systems in parallel. Heres what the Scheduler looks like:

struct Scheduler {
    systems: Vec<Node>,
}

struct Node {
    // the function that will be run
    system: Box<dyn System + Send + Sync>,
    // the data that this system accesses  
    // "Accessor" is an enum. Used to compute systems that conflict with this one
    access: Vec<Accessor>,
    // Contains all the systems without any conflicts.
    edges: Vec<usize>,
}

Each Node contains a System. Whenever a Node is created, I compute all the other systems which will not conflict with the System when ran. This will allow me run them in parallel if possible without the risk of deadlock.

Here's my code for executing the systems:

    pub fn execute(&mut self, engine: Arc<Engine>) {
        // for every system...
        for i in 0..self.systems.len() {
            // if it has not been ran...
            if !self.systems[i].has_ran {    
                // run the system
                rayon::spawn(|| self.systems[i].system.execute(engine.clone())); // <-- error occurs here

                // spawn threads for every system in `edges`, not implemented yet.
            }
        }
    }
#

Cargo Check outputs this:

error[E0521]: borrowed data escapes outside of method
  --> src/scheduler.rs:47:17
   |
44 |     pub fn execute(&mut self, engine: Arc<Engine>) {
   |                    ---------
   |                    |
   |                    `self` is a reference that is only valid in the method body
   |                    let's call the lifetime of this reference `'1`
...
47 |                 rayon::spawn(|| self.systems[i].system.execute(engine.clone()));
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |                 |
   |                 `self` escapes the method body here
   |                 argument requires that `'1` must outlive `'static`

error[E0373]: closure may outlive the current function, but it borrows `engine`, which is owned by the current function
  --> src/scheduler.rs:47:30
   |
47 |                 rayon::spawn(|| self.systems[i].system.execute(engine.clone()));
   |                              ^^                                ------ `engine` is borrowed here
   |                              |
   |                              may outlive borrowed value `engine`
   |
#
note: function requires argument type to outlive `'static`
  --> src/scheduler.rs:47:17
   |
47 |                 rayon::spawn(|| self.systems[i].system.execute(engine.clone()));
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `engine` (and any other referenced variables), use the `move` keyword
   |
47 |                 rayon::spawn(move || self.systems[i].system.execute(engine.clone()));
   |                              ++++

error[E0373]: closure may outlive the current function, but it borrows `i`, which is owned by the current function
  --> src/scheduler.rs:47:30
   |
47 |                 rayon::spawn(|| self.systems[i].system.execute(engine.clone()));
   |                              ^^              - `i` is borrowed here
   |                              |
   |                              may outlive borrowed value `i`
   |

Heres what I've tried:

1: Wrapping the system in a SyncUnsafeCell. same error.
2. Adding move as suggested by the compiler. didnt work.

Heres what the System trait looks like:

pub trait System: 'static {
    fn execute(&self, engine: Arc<Engine>);
    fn accessors(&self) -> Vec<Accessor>;
    fn queries(&self, queries: &mut Vec<Vec<ComponentId>>);
}

Any help is greatly appreciated.

#

[SOLVED] borrowed data escapes outside of method error when parallelizing functions

#

I've Solved it

#

what I ended up doing is wrapping Node.system in an Arc and cloning System and Engine outside of the closure.