Arc data not changing between threads

Hi there it's my first time here so apologies for mistakes about the language, I'm still learning it

With that said, I'm also a beginner at multi-threaded applications so I may have the wrong concepts in my head about the structures I'm trying to use

My task is to create a simple multi threaded particle simulation, to start with, I create a threadpool to manage the movement of particles, and another for the collision detection + response.

The current structure looks like this:

  • Movement manager clones + locks a strip of the array
  • Movement manager does their stuff on the particle strip
  • Movement manager releases the lock and sends a message to the Collision manager, giving the index of the strip that is now free to be processed
  • Movement repeats this for all strips
  • Collision receives the index, clones + locks the arc strip data and does the collision detection + response (inverting x,y,z velocity on a particle if it exceeds the bounds)

When running with a strip size of 1, this works fine, however, when I try upping the strip count to 2+ , it leads to unclear results, where particles will completely ignore their bounds and simply keep moving.

It is almost as if the collision manager's changes to the velocity go unnoticed by the movement manager in the next frame of the simulation. I have been scratching my head for a few hours at this as I don't see why the changes aren't being kept, I understand that Arcs have a shared memory location, and therefore any changes made to a strip in one thread should persist into the other?

let strips = Arc::new( vec! [ Arc::new( Mutex::new ( vec![ particle;1 ] ) ); 2 ] );

This is my top-level code for creating the strips of particles

let move_particles = strips.clone();
let collision_particles = strips.clone();
...
let (tmc, rmc) : (Sender<usize>, Receiver<usize>)= mpsc::channel(); 
...
let collision_manager = Arc::new(CollisionManager::new(width, depth, collision_particles));
let collision_join_handle = std::thread::spawn(move || CollisionBeginListening(collision_manager, rmc));
let movement_manager = MovementManager::new(tmc, move_particles);

Movement Manager

threadpool.scoped(|scope|{
   for i in 0..2{  //2 = number of strips
       let strip = self.particles[i].clone();
       scope.execute(move || move_function(strip));
       scope.join_all();
       self.transmitter.send(i).unwrap();
    }
});

move_function

let mut particles = strip.lock().unwrap();
for i in 0..particles.len(){
   let vel = particles[i].get_velocity();
   particles[i].move_particle();
}

Collision Manager

threadpool.scoped(|scope|{
    loop{
        let index = receiver.recv().unwrap();
        let strip = cm.particles[index].clone();
        scope.execute(move || collide_function(strip, width, depth));
        scope.join_all();
    }
}); 

collide_function

let mut particles = strip.lock().unwrap();
for i in 0..particles.len(){
    let pos = particles[i].get_position();
    if pos[0] > 0.5 || pos[0] < -0.5{
        particles[i].invert_x_velocity();
    }
    if pos[1] < 0.0 || pos[1] > 2.0{
        particles[i].invert_y_velocity();
    }
    if pos[2] > 0.5 || pos[2] < -0.5{
         particles[i].invert_z_velocity();
    }
}

Any help is appreciated because I'm stuck in a rut of not understanding, many thanks

Unless you are using Arc::make_mut, then the changes really are visible to other threads.

1 Like

Thanks for the suggestion @alice , I wasn't using make_mut but I seem to have fixed it, I was using the movement manager in the main thread, but by swapping it out to it's own thread, the problem seems to have fixed itself. I'm unsure as to why running that in the main thread was causing issues