首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++11无锁更新2变量原子化

C++11无锁更新2变量原子化
EN

Stack Overflow用户
提问于 2014-07-18 13:01:29
回答 1查看 1.4K关注 0票数 4

当线程找到一个新的最小值以将其更改为atomicX时,我想更新它。当它确实设置了新的最小值时,我还想改变一个变量y,原子化。有办法不用锁吗?

在多个线程上同时执行线程函数的示例:

代码语言:javascript
复制
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;
}

我可以用锁做这件事:

代码语言:javascript
复制
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条件两次,或者我必须打破循环。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-07-18 15:41:29

有一个相当简单且可能是可移植的解决方案,即使用指针和CAS:

代码语言:javascript
复制
struct XY {
  uint64_t x;
  uint32_t y;
};
std::atomic<XY *> globalXY;

然后,棘手的问题变成了如何分配和释放这些对象,而没有过多的成本或ABA问题。

为了清晰起见,代码将以如下方式结束:

代码语言:javascript
复制
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实例就足够了。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24825690

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档