C++ 为单个线程强制执行语句的相对顺序
我希望确保以下三条语句按照指定的确切顺序执行:C++ 为单个线程强制执行语句的相对顺序,c++,c++11,lock-free,memory-barriers,C++,C++11,Lock Free,Memory Barriers,我希望确保以下三条语句按照指定的确切顺序执行: auto t1 = std::chrono::steady_clock::now(); // Statement 1 auto t2 = std::chrono::system_clock::now(); // Statement 2 auto t3 = std::chrono::steady_clock::now(); // Statement 3 编译器(或处理器)可以自由地对这些语句重新排序,因为没有数据依赖关系。看 C++11添加了std
auto t1 = std::chrono::steady_clock::now(); // Statement 1
auto t2 = std::chrono::system_clock::now(); // Statement 2
auto t3 = std::chrono::steady_clock::now(); // Statement 3
编译器(或处理器)可以自由地对这些语句重新排序,因为没有数据依赖关系。看
C++11添加了std::atomic_signal_fence
,以“按照顺序的指示,在线程和在同一线程上执行的信号处理程序之间建立非原子和放松的原子访问的内存同步顺序”。然而,根据cppreference,“没有发出内存顺序的CPU指令”所以我不清楚这将如何阻止处理器重新排序
我的问题是:
以下代码是否足以阻止编译器对语句进行重新排序(假设它对所有代码都有本地定义)
处理器是否可以自由地重新安排这些操作的顺序?e、 g.它能执行它们2-1-3吗?如果是这样的话,std::atomic\u thread\u fence
会阻止它吗
我是否需要引入人工数据依赖项(如链接问题中所述)以获得预期的行为?您不需要做任何事情来阻止编译时重新排序;非内联函数调用是可能通过全局变量相互作用的黑盒,因此编译器无法对它们重新排序 或者如果
std::chrono::staid_clock::now()
可以完全内联(可能使用内联asm读取时间戳),now()
的正确实现将使用类似于volatile
访问或GNU Casm volatile
的方法来确保它不能与其他now()
调用一起重新排序。(更重要的是,要确保它不能CSE和被吊出一个循环,从而产生一种所有事情都花费零时间的错觉)
与您链接的问题不同,您关心的排序不是简单的计算,如z=x+y代码>
它们是对通常为库函数的特殊函数调用。我没有检查规格,但是如果时间获取函数有某种关于被wrt订购的规则,我也不会感到惊讶。彼此当然,一个高质量的实现会希望为您做到这一点
处理器是否可以自由地重新安排这些操作的顺序 这是半真半假的。在实际实现中不太可能,通常
now()
运行相当多的指令,其大小与无序执行窗口相当。(例如,Skylake上的ROB大小为224 uops。一个rdtsc
仅为20 uops,并且有大量的缩放工作)
OoO exec通常是在最早的就绪优先的基础上执行的,因此同一个now()
函数的多次重复不太可能按顺序执行
如果系统时钟
和稳定时钟
使用完全不同的现在
,并且现在
本身不进行任何限制,则可能需要使用特定于实现的机制来阻止OoO exec。e、 g.在x86上,\u mm\u lfence()
e、 g.如果system\u clock
具有较低的开销now
,仅读取易失性内存位置(在内核导出的页面中,由中断处理程序更新),但稳定的时钟::now
使用rdtsc
,则重新排序是合理的。但是没有办法阻止它
然而,根据cppreference,“没有发布用于内存排序的CPU指令”,因此我不清楚这(原子信号围栏
)将如何阻止处理器重新排序
没有。这不是重点,也不是目的。无序执行确保保持它按程序顺序运行的假象(对于单个线程)
<> P> >代码> AddioSigSaleSaveAlgWave/Cuff>只需要确保ASM程序顺序与在同一线程中运行的信号处理程序(或同一核心上的中断处理程序)匹配C++抽象机源顺序,以观察该线程在程序顺序中的操作。反之亦然,对于由信号处理程序完成的存储
你是对的,你的尝试不起作用。它只可能对允许对now()
函数进行编译时重新排序的(IMHO-breaked)实现有所帮助,然后可能只是作为如何定义原子信号围栏()
的副作用。e、 例如GNU Casm volatile(“:“内存”)
。虽然如果now()
被破坏,并使用非volatile
asm语句(因此多个now()
调用可能会相互冲突),但是asm volatile
语句不会对它们进行排序。非内联函数调用不一定是黑框。整个程序优化器看到了很多,一些编译器有标准库调用的表。@ArchD.Robison:是的,我的措辞过于简单;即使没有实际的内联,也可能发生IPO(过程间优化)。但是大多数非模板库函数都是不透明的,只有像sqrt
,printf
,当然还有memcpy
,strcpy
等最关键的函数被视为编译器内置函数。但是,一个实现工作,如果实践中重新调用它自己的标准库<代码>现在()/代码>函数> .ARCH.RoBys:整个程序/链接时间优化通常不会发生在库中,那么我会认为它被破坏了;它们通常不是构建为机器代码+中间表示(如LLVM字节码或GCC GIMPLE)的胖二进制文件。不需要中间表示。所需要的只是副作用的总结。我想我见过一个封闭源代码编译器为自己的库构建这样的摘要。但是我同意一个不尊重now()
的编译器会被认为是坏的。@ArchD.Robison:interest;有了gcc和clang,要么是完全LTO,要么什么都没有。但这是有道理的,有点纯洁
auto t1 = std::chrono::steady_clock::now(); // Statement 1
std::atomic_signal_fence(std::memory_order::memory_order_release);
auto t2 = std::chrono::system_clock::now(); // Statement 2
std::atomic_signal_fence(std::memory_order::memory_order_release);
auto t3 = std::chrono::steady_clock::now(); // Statement 3
std::atomic_signal_fence(std::memory_order::memory_order_release);