Atomic memory ordering question - regarding a thread "stop" flag

⚓ Rust    📅 2025-12-08    👤 surdeus    👁️ 1      

surdeus

So, I have an application that starts multiple "worker" threads.

Usually, each "worker" thread simply finishes after it has done all of its assigned work. And the "main" thread will join() all of the "worker" threads to ensure that everything is completed.

But, sometimes, it can happen that one "worker" thread encounters an error and returns early. In this case, we want to signal to the other "worker" threads that they should abort ASAP, because it would not make sense to wait for the other "worker" threads to actually finish their work, when we already know that something failed. So what we need is some sort of global "stop" flag.

A common way to implement this is by using an AtomicBool:

static STOP: AtomicBool = AtomicBool::new(false);

fn worker_thread() {
    while !STOP.load(...) {
        /*
        do the next chunk of work here, if not stopped yet!
        */

        if error_happened {
            STOP.store(true, ...);
            break;
        }
    }
}

Now, the big question is: which Ordering should be used here?


I have read various sources on this topic, but the information is inconclusive :exploding_head:

Some sources say that Ordering::Relaxed is sufficient for this use case, because atomic operation always are "atomic", and the memory ordering only becomes relevant, if we need to synchronize the atomic operation with other loads and/or stores. Since this is not the case here, we can simply use the weakest (fastest), memory ordering, i.e., Ordering::Relaxed.

But other sources claim that if we update (store) the "stop" flag with Ordering::Relaxed, or if we test (load) the "stop" flag with Ordering::Relaxed, then the updated value that is stored by one thread may not become "visible" to other threads for an indefinite amount of time – possibly never. To ensure that the updated value becomes visible to other threads soon, we need to do the store with Ordering::Release, and we need to do the loads with Ordering::Acquire.

Which statement is correct? :confused:

I would like to stick with Ordering::Relaxed, especially for the load, because this happens at high frequency in the "worker" threads, so we really want this to be as fast as possible. And it seems to work fine in my tests. But this, of course, is not a proof that it will always work...

Best regards.

1 post - 1 participant

Read full topic

🏷️ Rust_feed