如何有效地使用std :: atomic [英] How to use std::atomic efficiently

查看:268
本文介绍了如何有效地使用std :: atomic的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

std :: atomic是c ++ 11引入的新功能,但我找不到有关如何正确使用它的教程。

std::atomic is new feature introduced by c++11 but I can't find much tutorial on how to use it correctly. So are the following practice common and efficient?

我使用的一个实践是我们有一个缓冲区,我想在某些字节上使用CAS,所以我做的是:

One practice I used is we have a buffer and I want to CAS on some bytes, so what I did was:

uint8_t *buf = ....
auto ptr = reinterpret_cast<std::atomic<uint8_t>*>(&buf[index]);
uint8_t oldValue, newValue;
do {
  oldValue = ptr->load();
  // Do some computation and calculate the newValue;
  newValue = f(oldValue);
} while (!ptr->compare_exchange_strong(oldValue, newValue));

所以我的问题是:


  1. 上面的代码使用了丑陋的reinterpret_cast,这是检索引用位置& buf [index]的原子指针的正确方法吗?

  2. 一个字节明显比CAS上慢一个机器字,这样我应该避免使用它吗?我的代码看起来更复杂,如果我改变它加载一个字,提取字节,计算和设置新的值中的字节,并做CAS。这使代码更复杂,我也需要自己处理地址对齐。

编辑:如果这些问题是处理器/ ,那么x86 / x64处理器的结论是什么?

if those questions are processor/architecture dependent, then what's the conclusion for x86/x64 processors?

推荐答案


  1. $ c> reinterpret_cast 会产生未定义的行为。您的变量是 std :: atomic 或一个简单的 uint8_t 你不能在他们之间施放。例如,尺寸和对准要求可以不同。例如一些平台只提供对单词的原子操作,所以 std :: atomic< uint8_t> 将使用一个完整的机器字,其中纯文本 uint8_t 只能使用一个字节。非原子操作也可以以各种方式优化,包括与周围操作显着地重新排序,并且与可以提高性能的相邻存储器位置上的其他操作组合。

  1. The reinterpret_cast will yield undefined behaviour. Your variable is either a std::atomic<uint8_t> or a plain uint8_t; you cannot cast between them. The size and alignment requirements may be different, for example. e.g. some platforms only provide atomic operations on words, so std::atomic<uint8_t> will use a full machine word where plain uint8_t can just use a byte. Non-atomic operations may also be optimized in all sorts of ways, including being significantly reordered with surrounding operations, and combined with other operations on adjacent memory locations where that can improve performance.

这意味着如果你想对某些数据进行原子操作,那么你必须提前知道,并创建合适的 std :: atomic< > 对象,而不仅仅是分配一个通用缓冲区。当然,您可以分配一个缓冲区,然后使用放置 new 来初始化该缓冲区中的原子变量,但是您必须确保大小和对齐方式正确,你将不能对该对象使用非原子操作。

This does mean that if you want atomic operations on some data then you have to know that in advance, and create suitable std::atomic<> objects rather than just allocating a generic buffer. Of course, you could allocate a buffer and then use placement new to initialize your atomic variable in that buffer, but you'd have to ensure the size and alignment were correct, and you wouldn't be able to use non-atomic operations on that object.

如果你真的不关心对原子对象的排序约束,那么使用 memory_order_relaxed ,否则将是非原子操作。但是,请注意,这是高度专业化,需要非常仔细。例如,对不同变量的写入可能被其他线程以不同于它们被写入的顺序读取,并且不同的线程可以以不同的顺序读取值,即使在程序的相同执行内。

If you really don't care about ordering constraints on your atomic object then use memory_order_relaxed on what would otherwise be the non-atomic operations. However, be aware that this is highly specialized, and requires great care. For example, writes to distinct variables may be read by other threads in a different order than they were written, and different threads may read the values in different orders to each other, even within the same execution of the program.

如果CAS对一个字节比一个字慢,您可以使用 std :: atomic< unsigned& ,但是这将有一个空间惩罚,你肯定不能使用 std :: atomic< unsigned> 字节---对该数据的所有操作必须通过相同的 std :: atomic< unsigned> 对象。

If CAS is slower for a byte than a word, you may be better off using std::atomic<unsigned>, but this will have a space penalty, and you certainly can't just use std::atomic<unsigned> to access a sequence of raw bytes --- all operations on that data must be through the same std::atomic<unsigned> object. You are generally better off writing code that does what you need and letting the compiler figure out the best way to do that.



许多情况下,它是一样快,而且更少的错误倾向,使用锁而不是原子操作。如果互斥锁的开销是重要的,由于争用,那么你可能需要重新思考你的数据访问模式---缓存乒乓可能会打击你用原子论。

In many cases it is just as fast, and a lot less error-prone, to use locks rather than atomic operations. If the overhead of a mutex lock is significant due to contention then you might need to rethink your data access patterns --- cache ping pong may well hit you with atomics anyway.

这篇关于如何有效地使用std :: atomic的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆