为什么在获取系统时间时使用`atomic_signal_fence`

时间:2018-01-17 15:38:03

标签: c++ concurrency atomic barrier

我在github repo中找到了这个函数,它实现了一个无锁队列。此函数使用QueryPerformanceCounter来获得准确的系统时间。

#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);
}

我注意到有两个CompilerMemBar(),我认为这是为了防止编译器重新排序。但是,在我搜索github上的一些代码之后,我发现带有编译器障碍的包QueryPerformanceCounter可能不常见。所以我的问题是这些障碍来处理一些特殊情况?可能是一个可能的重新排序会影响我们得到的系统时间的精度吗?但我无法弄清楚它们将如何做,因为我认为即使WINAPI调用或return语句被重新排序,它似乎也没有影响精度。

1 个答案:

答案 0 :(得分:2)

如果编译器无法重新排序语句,代码开发人员可能认为它会产生更准确的结果。 例如:

result = optimize.minimize(fun, initial_guess,args=additional,constraints=cons,method='SLSQP',
                           options={'xtol': 1e-8, 'disp': True})

如果您想在两次昂贵的调用之间获得确切的时间戳(或性能计数),那么您不希望编译器使用其中一个重新排序expensive1(); // takes a lot of time SystemTime t = getSystemTime(); expensive2(); 因为它可能会影响getSystemTime()返回的值。

这是否切合实际,我不知道。编译器必须知道函数内部发生了什么,否则它不会重新排序任何东西 (如果QueryPerformanceCounter调用是在预编译库中定义的,则无论如何都不会重新排序语句。)

但至少这种做法似乎没有太大的危害。 expensive阻止编译器重新排序,但它不会产生CPU fence指令。