Search code examples
c++concurrencyatomicbarrier

Why a `atomic_signal_fence` is used here when getting system time


I found this function in a github repo which implements a lockfree queue. This function uses the QueryPerformanceCounter to get accurate system time.

#define CompilerMemBar() std::atomic_signal_fence(std::memory_order_seq_cst)
SystemTime getSystemTime()
{
    LARGE_INTEGER t;
    CompilerMemBar();
    if (!QueryPerformanceCounter(&t)) {
        return static_cast<SystemTime>(-1);
    }
    CompilerMemBar();

    return static_cast<SystemTime>(t.QuadPart);
}

I noticed there are two CompilerMemBar(), which I thought is intented to prevent compiler from re-ordering. However, after I searched some codes on github, I found wrapping QueryPerformanceCounter with compiler barriers may not be a common practice. So my question is these barriers here to handle some special situations? May be a possible reorder will affect the precision of system time we get? But I can't figure out how they will do, because I think even either the WINAPI call or the return statement is reordered, it seems to have no influence on the precision.


Solution

  • The code developer may have believed that it would produce more accurate results if the compiler could not reorder statements.. For example:

    expensive1(); // takes a lot of time
    
    SystemTime t = getSystemTime();
    
    expensive2();
    

    If you want the exact timestamp (or performance count) in between both expensive calls, you don't want the compiler to reorder getSystemTime() with one of them because it might have impact on the value returned by QueryPerformanceCounter.

    Whether that is realistic, I don't know. The compiler has to know what is happening inside the function or it won't reorder anything (if the expensive calls are defined in a pre-compiled library, no reordering of statements will take place anyway).

    But at least this approach does not seem to do much harm. std::atomic_signal_fence(std::memory_order_seq_cst) prevents the compiler from reordering, but it does not produce CPU fence instructions.