我想在线程找到新的最小值时更新atomicX
以将其更改为。当它设置新的最小值时,我还想以原子方式更改变量y
。有没有办法在没有锁的情况下做到这一点?
一次在多个线程上执行的线程函数示例:
uint64_t x = atomicX;
int y = g();
for(int newX = 0; newX < x; ++newX)
{
if(f(newX))
{
while(newX < x && !atomicX.compare_exchange_strong(x, newX));
// also set atomicY to y if the exchange happened above
break;
}
x = atomicX;
}
我可以用锁来做到这一点:
int y = g();
for(uint64_t newX = 0; newX < atomicX; ++newX)
{
if(f(newX))
{
mutex.lock();
if(newX < atomicX)
{
atomicX = newX;
atomicY = y; // atomicY no longer needs to be atomic
}
mutex.unlock()
break;
}
}
我也愿意接受任何更清晰的结构,或者另外一种方式来完成这一切。我不喜欢我必须两次具有相同的newX < x
条件,或者我必须打破循环。
答案 0 :(得分:1)
这是一个相当简单且可能足够便携的解决方案,即使用指针和CAS:
struct XY {
uint64_t x;
uint32_t y;
};
std::atomic<XY *> globalXY;
然后,这个棘手的问题就变成了如何在没有过多成本或ABA问题的情况下分配和释放这些对象。
为清楚起见,代码最终会是这样的:
XY *newXY = somehow_allocate_objects();
XY *oldXY = globalXY;
int oldX = oldXY->x;
newXY->y = g();
for(int newX = 0; newX < oldX; ++newX) {
if(f(newX)) {
// prepare newXY before swapping
newXY->x = newX;
while(newX < oldX && !globalXY.compare_exchange_strong(oldXY, newXY)) {
// oldXY was updated, reload oldX
oldX = oldXY->x;
}
// globalXY->x,y both updated by pointer CAS
break;
}
oldXY = globalXY;
oldX = oldXY->x;
}
作为参考,最终的结论是这些线程是长寿的,因此为每个线程静态分配单个XY
实例就足够了。