最近我在 c++ 中大量使用原子序数,因为我使用线程太多并且线程安全对我来说很重要
好吧,我在 printf() 函数上遇到了问题,这里有一个例子
atomic_uint64_t count = {0}
printf("%lu",count);
// It gives error couple of errors like atomic(cost atomic&) = delete; and use of deleted function atomic so i had to write it like this to make it work
printf("%lu",count.load());
// Or
printf("%lu",(uint64_t)count);
好吧,无论如何,我不知道哪个对性能更好,我真的很关心速度
所以我开始考虑哪个更好检索值并在 if 条件或其他任何地方使用它
喜欢
if(count.load() < 8 ){
// Do smth
}
或
if(count < 8){
// Do smth
}
哪个对速度和性能更好,谢谢。
它们的含义完全相同(除非您传递像count.load(std::memory_order_acquire)
这样的非默认内存顺序)。
我希望所有 ISA 中所有编译器的生成程序集没有差异,当然启用优化。我在 https://godbolt.org/上看过的代码中没有GCC/clang/MSVC/ICC。 无论它内联到什么周围的代码中,都是如此。
如果存在差异,并且一个较慢或需要更大的代码大小,请在您使用的任何编译器中将其报告为错过的优化编译器错误。 (除非您禁用了优化,否则可以对包装器函数进行额外级别的调用。
至于错误,那是因为您正在一个尚未暗示类型的上下文中评估它:作为可变参数函数的操作数 (printf
)。
如果有足够的上下文暗示您希望从atomic<T>
获得基础 T 值(这就是atomic_uint64_t
),则调用operator T()
重载,它被记录为等效于.load()
。 分配和.store()
相同的交易.
没有任何其他函数可以让你只访问原子64位整数的低32位(不幸的是);即使在32位机器上,当前的编译器实际上也会麻烦地执行64位原子加载(这在某些32位机器上是有效的,在其他机器上不是),然后如果你将值转换为较窄的类型,则丢弃高32位。(这是一个错过的优化,但编译器目前确实没有优化原子。
因此,没有歧义可以通过.load
来解决,或者演员可以选择不同的负载的任何方式。
存在.load()
和.store()
的一个原因是它们采用std::memory_order
参数,该参数默认为seq_cst
,但如果您只需要原子性但只需要线程之间的 acq/rel 同步,则可能会更弱。 或者根本没有relaxed
,只有原子性。
另一个原因是让你编写foo.load()
来提醒你的代码读者这是一个原子变量,而不仅仅是一个普通的基元类型。 出于这种风格原因,我更喜欢count.load()
. 大概如果你把它的类型从uint64_t
,你会想改变你的打印方式,而不是仍然把它投射到uint64_t
。 使用.load()
将允许编译器在您更改其类型时警告您格式字符串不匹配。