Synchronization via compare_exchange failure

⚓ Rust    📅 2026-06-09    👤 surdeus    👁️ 2      

surdeus

I'm wondering what level of synchronization the failure case of compare_exchange provides

    static mut VALUE: u64 = 0;

    pub fn some_func() {
        let flag = Arc::new(AtomicBool::new(false));

        let flag1 = flag.clone();
        let flag2 = flag.clone();
        let h1 = thread::spawn(move || thread_a_runner(&flag1));
        let h2 = thread::spawn(move || thread_b_runner(&flag2));

        h1.join().unwrap();
        let result = h2.join().unwrap();
        assert_ne!(0, result);
    }

    fn thread_a_runner(flag: &AtomicBool) {
        unsafe { VALUE = 1 }
        flag.store(true, Ordering::Release);
    }

    fn thread_b_runner(flag: &AtomicBool) -> u64 {
        std::thread::sleep(Duration::from_nanos(100));
        let mut value = 2;
        if flag
            .compare_exchange(false, false, Ordering::Relaxed, Ordering::Acquire)
            .is_err()
        {
            unsafe {
                value = VALUE;
            }
        }
        value
    }

In this code, does the failure ordering of the compare_exchange synchronize with the store and therefore ensure that VALUE is set to 1 (if the timing is right and the failure actually occurs)?
If thread B sleeps long enough to have thread A finish and then also observes the change of the flag, the compare_exchange should fail, in which case the if-block is entered. Because the failure case uses acquire ordering and the storing uses release ordering, I would assume that VALUE is therefore always 1 if the if-block is entered.
(This is obviously in no way sensible code to write but it was the quickest example I could come up with to illustrate the question)

2 posts - 2 participants

Read full topic

🏷️ Rust_feed