无锁的原子函数改变两个独立的内存位置

Posted

技术标签:

【中文标题】无锁的原子函数改变两个独立的内存位置【英文标题】:Atomic function without locks to change two independent memory locations 【发布时间】:2017-05-01 09:02:28 【问题描述】:

我有一个名为updateEntry 的函数,它将一个值写入查找表。我想创建这个函数的多线程版本。 我正在研究原子操作__sync_bool_compare_and_swap,但我不确定如何在此处正确应用它。

理论上是否可以在不锁定的情况下自动实现此功能,因为它会更改两个独立的内存位置entryLookup[id]entry

   void updateEntry(Entry ** entryLookup, unsigned int id, int val1, short val2)
            Entry * entry     = entryLookup[id];
            entry->val1       = val1;
            entry->val2       = val2;
            entryLookup[id]  += sizeof(Entry);
   

【问题讨论】:

问题:1) 你能确保每个线程都能访问不相交的id 集合吗? 2) 你能保证修改val1val2 不会影响entryLookup operator[] 结果吗? 3) 你能确保修改entryLookup 的值不会影响任何并行线程(例如,新的id 不会被任何其他线程访问)?如果其中任何一条规则不匹配,我认为实现无锁并发会很困难。 @AdrianMaire 非常感谢您的回答。我构建了一个使用不相交 id 集的解决方案,但生成这种不相交集的成本很高。我想避免使用不相交的 ID 集。第 2 点是什么意思。)? Q4 - 更新是否与查找同步?如果没有,您可以首先自动更新entryLookup[id],确保没有其他线程会使用相同的条目,然后在您闲暇时更新值(有点)。如果还要进行查找,则必须同时更新两个单独的位置,而这不能使用原始原子操作来完成。 定义“无锁定”——你总是可以使用原子的“正在更新”标志 我不知道entryLookup 是什么样子:我可以想象一个类,其中operator[] 被重载并访问val1。想象一个第一个线程,访问 id=5,它返回 0x42 处的条目,在修改 val1 之后,entryLookup 现在对应于(例如)id=10。下一个线程访问 id=10 也对应于 0x42 处的条目。现在两个线程在没有锁的情况下同时访问同一个对象。 【参考方案1】:

为了使这个线程安全,您可以先增加entryLookup[id] 以确保稍后出现的任何其他线程不能更改相同的条目,然后填写值。返回旧值的地方需要原子加法:

void updateEntry(Entry ** entryLookup, unsigned int id, int val1, short val2)

    Entry * entry = __sync_fetch_and_add(&entryLookup[id], sizeof(Entry));
    entry->val1   = val1;
    entry->val2   = val2;

【讨论】:

我刚刚注意到@eran 已经在 cmets 中给出了这个答案。 这很简单,应该可以解决我的问题。非常感谢这个很棒的答案。 @peppincsoda 这里的问题是两个val 条目的修改从未发布(同步)。如何在另一个线程中安全地访问entry 请注意,仅当更新阶段在执行查找之前结束时,这才是安全的。否则,查找可能会在设置其值之前看到一个条目。此外,正如@LWimsey 评论的那样,更新结束时应该存在一些写入障碍(即使没有明确请求刷新,这种代码也可能会起作用,但访问这些值仍将被视为数据竞争)。 你说得对,我假设提问者不想在从多个线程更新结构时进行查找。

以上是关于无锁的原子函数改变两个独立的内存位置的主要内容,如果未能解决你的问题,请参考以下文章

我们可以用两个或多个无锁容器原子地做一些事情而不锁定两者吗?

Redis学习笔记29——无锁的原子操作:Redis如何应对并发访问

Redis学习笔记29——无锁的原子操作:Redis如何应对并发访问

JMMsynchronized原理可见性有序性happens-beforeCAS(无锁并发)原子性 synchronized的优化

JMMsynchronized原理可见性有序性happens-beforeCAS(无锁并发)原子性 synchronized的优化

CAS原子锁 高效自旋无锁的正确用法