How to correctly use std::atomic_signal_fence()?

No, your code does not demonstrate correct usage of atomic_signal_fence. As you quote cppreference.com, atomic_signal_fence only perform synchronization between a signal handler and other code running on the same thread. That means that it does not perform synchronization between two different threads. Your example code shows two different threads.

The C++ spec contains the following notes about this function:

Note: compiler optimizations and reorderings of loads and stores are inhibited in the same way as with atomic_thread_fence, but the hardware fence instructions that atomic_thread_fence would have inserted are not emitted.

Note: atomic_signal_fence can be used to specify the order in which actions performed by the thread become visible to the signal handler.

Here's an example of correct, if not motivating, usage:

static_assert(2 == ATOMIC_INT_LOCK_FREE, "this implementation does not guarantee that std::atomic<int> is always lock free.");

std::atomic<int> a = 0;
std::atomic<int> b = 0;

extern "C" void handler(int) {
    if (1 == a.load(std::memory_order_relaxed)) {
        std::atomic_signal_fence(std::memory_order_acquire);
        assert(1 == b.load(std::memory_order_relaxed));
    }

    std::exit(0);
}

int main() {
    std::signal(SIGTERM, &handler);

    b.store(1, std::memory_order_relaxed);
    std::atomic_signal_fence(std::memory_order_release);
    a.store(1, std::memory_order_relaxed);
}

The assertion, if encountered, is guaranteed to hold true.


In your example, you want to use std::atomic_thread_fence (which generates machine code to perform thread synchronization); not std::atomic_signal_fence (which only disables compiler memory reordering optimizations on atomic variables). As was said by others, std::atomic_signal_fence is only intended for signals on the same thread as the atomic operations (I believe it would also hold true for structured/vectored exception handlers on Windows, but don't quote me on that).