C++ 我们可以用2个或更多无锁容器来做一些原子化的事情,而不同时锁定这两个容器吗?
我正在寻找-使用事务性内存非常容易做到。(感谢阿米·塔沃里) 使用锁(mutex/spinlock)很容易做到,但可能会导致死锁,因此基于锁的算法只能通过手动调整组合 无锁算法不存在死锁问题,但它是不可组合的。需要将2个或多个容器设计为单个组合的无锁数据结构 是否有任何方法、帮助器实现或一些无锁算法-以原子方式使用多个无锁容器来保持一致性C++ 我们可以用2个或更多无锁容器来做一些原子化的事情,而不同时锁定这两个容器吗?,c++,multithreading,concurrency,lock-free,libcds,C++,Multithreading,Concurrency,Lock Free,Libcds,我正在寻找-使用事务性内存非常容易做到。(感谢阿米·塔沃里) 使用锁(mutex/spinlock)很容易做到,但可能会导致死锁,因此基于锁的算法只能通过手动调整组合 无锁算法不存在死锁问题,但它是不可组合的。需要将2个或多个容器设计为单个组合的无锁数据结构 是否有任何方法、帮助器实现或一些无锁算法-以原子方式使用多个无锁容器来保持一致性 检查一个项目是否同时在两个容器中 以原子方式将元素从一个容器移动到另一个容器 或者,RCU或危险指示灯可以帮助做到这一点吗 众所周知,我们可以使用无锁容
- 检查一个项目是否同时在两个容器中
- 以原子方式将元素从一个容器移动到另一个容器
::包含(K常量和键)
-::获取(K const&key)
并更新我们获取的元素,我们应该使用lock:typedef cds::container::SkipListMap< cds::urcu::gc< cds::urcu::general_buffered<> >, int, foo, my_traits > skip_list;
skip_list theList;
// ...
typename skip_list::raw_ptr pVal;
{
// Lock RCU
skip_list::rcu_lock lock;
pVal = theList.get( 5 );
if ( pVal ) {
// Deal with pVal
//...
}
}
// You can manually release pVal after RCU-locked section
pVal.release();
typedef cds::container::SkipListMap,int,foo,my\u traits>跳过列表;
跳过列表;
// ...
typename skip_list::raw_ptr pVal;
{
//锁定控制单元
跳过列表::rcu锁定;
pVal=列表获取(5);
if(pVal){
//处理pVal
//...
}
}
//在RCU锁定区段后,您可以手动释放pVal
pVal.release();
但是,如果我们使用2个无锁容器而不是1个,并且如果我们只使用始终无锁的方法,或者其中一个无锁的方法,那么我们可以在不锁定两个容器的情况下进行操作吗
typedef cds::urcu::gc< cds::urcu::general_buffered<> > rcu_gpb;
cds::container::SkipListMap< rcu_gpb, int, int > map_1;
cds::container::SkipListMap< rcu_gpb, int, int > map_2;
typedefcds::urcu::gcrcu\u gpb;
cds::container::SkipListMapmap\u 1;
cds::container::SkipListMapmap\u 2;
我们能否在不锁定两个容器的情况下,将1个元素从map_1
自动移动到map_2
——即,如果我们想保持原子性和一致性:
- 其他线程看不到第一个容器中没有元素,他仍然没有出现在第二个容器中
- 其他线程看不到第一个容器中有元素,而第二个容器中已经有相同的元素
此外,“但可能会有一些额外的开销”,如果您对无锁算法进行了复杂的自定义改进,那么您可以提供一些可组合性,例如,正如Peter Cordes所指出的,“两个队列相互了解,查看它们的代码是经过精心设计的” TL:DR:正如雅克所指出的,你所问的没有多大意义。但是,由于您只要求一种不锁定两个容器的方法,因此您可以做一些事情。如果这不是你想要的,那么这可能有助于说明你如何提出这个问题的一个问题
在其中一个容器上安装一个可轻松进行,并解决观察两个容器的问题。 但是,永远不允许对您锁定的容器进行无锁访问,因此使用无锁容器是毫无意义的 如果您在观察无锁容器时持有锁定容器上的读锁,那么您在观察无锁容器时所了解到的关于锁定容器的信息仍然是正确的
在锁定容器上设置写锁会阻止任何读卡器在移除元素时观察锁定的数据结构。因此,您将使用如下算法:
write_lock(A); // exclude readers from A
tmp = pop(A);
push(B, tmp);
write_unlock(A); // allow readers to observe A again, after both ops are done
向另一个方向移动节点的工作方式相同:在锁定容器上保持写锁的同时执行删除和添加操作
您可以通过将元素临时放在两个容器中而不是两个容器中(复制到临时容器)来保存复制
顺便说一句,@Ami指出,事务性内存可以支持 但是您的规范的主要问题是,不清楚您到底在试图阻止潜在的观察者观察什么,因为他们只能以一种顺序或另一种顺序观察两个无锁数据结构,而不是像@Yakk指出的那样以原子方式观察 如果你能控制观察者观察的顺序,以及作者写作的顺序,这可能就是你所需要的
如果需要在两个容器之间建立更强大的链接,则可能必须将它们设计为一个单独的无锁数据结构,以了解两个容器。容器不提供“检查项目是否在b中”
write_lock(A); // exclude readers from A
B.add(A[i]); // copy directly from A to B
A.remove(i);
write_unlock(A); // allow readers to observe A again, after both ops are done