-1
use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};
use std::thread;

fn main() {

    let mut arr = vec![1,2,3];
    let ptr = &mut arr as *mut Vec<i32>;
    println!("ptr : {:?}",ptr);
    // unsafe { (*ptr)[0] = 2; }
    let ptr_ref_1 = Arc::new(AtomicPtr::new(ptr));
    let a = thread::spawn(move || unsafe {
        let ptr_inner = (ptr_ref_1).load(Ordering::SeqCst);
        println!("ptr_inner_1 {:?}",ptr_inner);
        (*ptr_inner).push(4);
        println!("4 is done");
    });
    let ptr_ref_2 = Arc::new(AtomicPtr::new(ptr));
    let b = thread::spawn(move || unsafe {
        let ptr_inner = (ptr_ref_2).load(Ordering::SeqCst);
        println!("ptr_inner_2 {:?}",ptr_inner);

        (*ptr_inner).push(5);
        println!("5 is done");
    });
    let ptr_ref_3 = Arc::new(AtomicPtr::new(ptr));
    let c = thread::spawn(move || unsafe {
        // Read value
        // println!("{:?}",*(ptr_ref_3.load(Ordering::SeqCst)));
        let ptr_inner = (ptr_ref_3).load(Ordering::SeqCst);
        println!("ptr_inner_3 {:?}",ptr_inner);

        (*ptr_inner).push(6);
        println!("6 is done");
    });
    a.join().unwrap();
    b.join().unwrap();
    c.join().unwrap();
    println!("final values {:?}",arr);
}

95% of the runs work fine , 5% of the runs throw the below error

Output : 

ptr : 0x16d65f008
ptr_inner_1 0x16d65f008
ptr_inner_2 0x16d65f008
5 is done
main(75339,0x16d867000) malloc: pointer 0x6000022a8010 being reallocated was not allocated
main(75339,0x16d867000) malloc: *** set a breakpoint in malloc_error_break to debug
Signal: SIGABRT (signal SIGABRT)

Trying to mutate multiple references to a single pointer of a vector using unsafe rust and threads. I understand how to use Arc/Mutex to update the values in multiple threads but not sure what's the error here with unsafe rust.

1 Answers1

6

This is a simple data race, since you're trying to mutate one Vec in three different threads without any synchronization. The fact that you're using AtomicPtr is doing nothing here. Usually when you use AtomicPtr<T>, it involves swapping it out for another T or a null pointer, modifying the original T, and then putting it back.

This code is always undefined behavior, but the 5% that actually crashes is probably because the Vec reallocates in one thread while another thread is trying to write to it.

This code would probably be best written with a channel.

drewtato
  • 6,783
  • 1
  • 12
  • 17
  • Understood. So if use the same code , just for parallel read purposes , this shouldn't throw any error right , since the vector isn't being modified? – Nikhil Chatragadda May 24 '23 at 08:43
  • @NikhilChatragadda The error isn't the problem, the undefined behavior is. Reading is fine, but this code isn't really ideal for any purpose. – drewtato May 24 '23 at 18:47