C 11原子锁定自由更新2个变量

我想在线程找到一个新的最小值来更新atomicX时更新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条件两次,或者我必须打破循环.

解决方法

一个相当简单且可能足够便携的解决方案,即使用指针和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实例就足够了.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...