我在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语句被重新排序,它似乎也没有影响精度。
答案 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指令。