0

This question is about standalone fences in C++

In an attempt to encapsulate the use of acquire and release fences, I have written the following code:

#include <thread>
#include <atomic>
#include <cassert>

class sync {
    std::atomic<bool> flag{false};

public:
    void release()
    {
        std::atomic_thread_fence(std::memory_order_release);
        flag.store(true, std::memory_order_relaxed);
    }

    bool acquire()
    {
        return flag.load(std::memory_order_relaxed);
        std::atomic_thread_fence(std::memory_order_acquire); // Is this acquire fence observed by the application ?
    }
};

int main()
{
    sync s;
    int data = 0;

    std::thread t1{[&] { data = 12; s.release(); }};
    std::thread t2{[&] { if (s.acquire()) assert(data==12); }};

    t1.join(); t2.join();
}

I believe that the fences are positioned correctly ('release' before the store and 'acquire' after the load).

I am not sure if the load/acquire actually works.
Since the acquire fence is after the load/return statement, I am wondering if it is taken into account at all.

Is this use of acquire fence correct ?

Tootsie
  • 655
  • 3
  • 11
  • I think you misunderstand the use of fences. Related: https://stackoverflow.com/a/56398731/5376789 – xskxzr Jun 27 '19 at 07:12
  • @xskxzr I put the fences in there based on information from [this article](https://preshing.com/20130922/acquire-and-release-fences/).. – Tootsie Jun 27 '19 at 13:18

1 Answers1

2

You cannot put the fence after the return. Your placement of the acquire fence is unreachable code. std::atomic_thread_fence is a function. Don't treat it as if it were a language feature. If you don't call the function, you don't get the effect.

I compiled your example in MSVC 19.16 (VS 2017 15.9.13) with compiler warning level 4 (/w4 flag). I got an "unreachable code" warning.

The GCC "unreachable code" warning was removed in version 4.5 https://stackoverflow.com/a/21240321/9107647

Fix (adapted from https://preshing.com/20130922/acquire-and-release-fences/):

bool acquire()
{
    if (flag.load(std::memory_order_relaxed))
    {
        std::atomic_thread_fence(std::memory_order_acquire);
        return true;
    }
    return false;
}
Humphrey Winnebago
  • 1,512
  • 8
  • 15