我目前正在开展一个具有非常严格的循环和实时要求的项目。过早优化绝对不是一个恶习。我想尽可能地利用C ++原子的可能relaxed
选项来实现我的目标。这是我的(线程不安全)设置:
// Shared data structure
uint8 data[100];
uint64 timeStamp = 0;
// Consumer threads 1...N run this
void loopConsume() {
uint64 lastTimeStamp = 0;
uint8 localData[100];
for (;;) {
while (timeStamp == lastTimeStamp);
memcpy(localData, latestData.data, 100);
lastTimeStamp = timeStamp;
doSomething(localData);
}
}
// Producer callback (singleton)
void produce(uint8 *newData) {
memcpy(latestData.data, newData, 100);
latestData.timeStamp++;
}
这是一个笨拙的(但表面上是正确的)尝试使用2个默认顺序一致性原子使其线程安全(和线程正确):
#include <atomic>
// Shared variables
uint8 data[100];
std::atomic<uint64> timeStamp = 0;
std::atomic<int32> numReaders = 0; // -1 means producer is writing
// Consumer threads 1...N run this
void loopConsume() {
uint64 lastTimeStamp = 0;
uint8 localData[100];
for (;;) {
uint64 t = timeStamp.load();
while (t == lastTimeStamp) t = timeStamp.load();
lastTimeStamp = t;
for (;;) {
int32 r = numReaders.load();
if (r >= 0 && numReaders.compare_exchange_weak(r, r + 1))
break;
}
memcpy(localData, data, 100);
doSomething(localData);
numReaders.fetch_sub(1);
}
}
// Producer callback (singleton)
void produce(uint8 *newData) {
while (!numReaders.compare_exchange_weak(0, -1));
memcpy(data, newData, 100);
timeStamp.fetch_add(1);
numReaders.store(0);
}
如您所见,存在大量原子操作,默认情况下所有操作都使用顺序一致性。我相当肯定他们中的许多人都可以放松。但是哪些?我可以减少操作或简化设置吗?
另一个问题是争论。我希望读者很少,并且他们可以快速将数据复制到本地变量。那么有一个真正的优势是有一个类型的读写锁(如上所述),或只是一个常规的互斥锁?如果在这种情况下常规互斥锁速度更快,我能否以某种方式将其合并到时间戳原子变量中?
非常感谢!