1

Note, this is a followup to: What are the options for safely modifying and reading a boolean across multiple threads and cpus?

I have some C++ code that contains roughly this logic:

class wrapper_info {
public:
        bool isConnected();
        void connectedHandler();
        void disconnectedHandler();
protected:
        std::atomic<bool> _connected;
}

void wrapper_info::connectedHandler() {
        _connected.store(true, std::memory_order_relaxed);
}

void wrapper_info::disconnectedHandler() {
        _connected.store(false, std::memory_order_relaxed);
}

bool wrapper_info::isConnected() {
        return _connected.load(std::memory_order_relaxed);
}

They are called in the following way:

Thread 1, 2, 3: isConnected()

Thread 2: connectedHandler() when the connection is initiated.

Thread 3 disconnectedHandler() when the connection is broken.

Is it sufficient to use memory_order_relaxed? It is my understanding that I would only need others like memory_order_release and memory_order_acquire when I want to ensure that other operations around it are seen by other threads. But I am just setting/reading a value. Thank you lots.

someone serious
  • 175
  • 1
  • 1
  • 7
  • 4
    As long as there are no other operations that would depend on the value being in expected state, yes, you can use relaxed setting here. Although, it might be tricky to prove, so unless your fences are really killing performance (how often are you going through reconnection cycle?), sequential model is easiest to understand and reason about. – SergeyA Sep 17 '21 at 18:13
  • 6
    Usually you have to dig a little deeper - *why* are you setting and reading this value? If, for instance, you are testing it to see whether some global resource is available, then you need a barrier to ensure that your access of the resource doesn't get reordered before the test. It's not a question you can answer in isolation. – Nate Eldredge Sep 17 '21 at 18:31
  • 3
    On another note, how will you do this without having a race? What happens if thread 1 tests `isConnected()` and goes on to do some stuff with the connection, but thread 3 disconnects the object before thread 1 actually gets started? – Nate Eldredge Sep 17 '21 at 18:34
  • Agreed with Nate; you maybe want some kind of reference-count for how many threads are currently wanting to keep the connection alive, and instead of checking `isConnected()`, a thread would increment that counter. If it had previously been zero, then you'd have to figure out whether a disconnect was in progress or had already happened. (Or hmm, even that's not sufficient; two threads could both try to claim, and the 2nd one could see the ref count go from 1 to 2 even though it had earlier been zero. So I guess before starting a disconnect, cmpxchg it to -999 or INT_MIN.) – Peter Cordes Sep 17 '21 at 21:55

1 Answers1

-1

It is really bad design as other guys mentioned already. Even if focus strongly on your question. That is not sufficient to use 'memory_order_relaxed' ! Because 'memory_order_relaxed' instructs not to do necessary variable synchronization. The code might have different values in different threads! Use 'memory_order_acq_rel' instead.

stanislav888
  • 362
  • 2
  • 9
  • `mo_relaxed` stores still become visible to all threads promptly, just not in any guaranteed order wrt. other loads and stores. You can't have a situation where some threads read it as true and other threads read it as false for a long time after one thread does a relaxed store. That minimal amount of synchronization is part of what `std::atomic` guarantees even with `mo_relaxed`. (And on real-world C++ implementations, it's a simple consequence of [the underlying hardware having coherent caches](https://stackoverflow.com/questions/4557979/when-to-use-volatile-with-/58535118#58535118)) – Peter Cordes Sep 18 '21 at 02:31
  • See also: [relaxed ordering and inter thread visibility](https://stackoverflow.com/q/56912520), and [Does a memory barrier ensure that the cache coherence has been completed?](https://stackoverflow.com/q/42746793) - cache coherence is separate from memory barriers, and happens even without them. Also [Is it possible that a store with memory\_order\_relaxed never reaches other threads?](https://stackoverflow.com/q/43749985) for the bare minimum the standard has to say. – Peter Cordes Sep 18 '21 at 02:38
  • Of course all of this is assuming that there's one store and then read-only by other threads. If a writer is frequently changing the value, readers will see different values whether they use relaxed, acq/rel, or seq_cst. Then see [Atomic operation propagation/visibility (atomic load vs atomic RMW load)](https://stackoverflow.com/q/55079321) for why "latest value" may not even make sense. – Peter Cordes Sep 18 '21 at 02:38