线程安全的C ++ std :: set,它支持来自多个线程的添加,删除和迭代器
-
05-07-2019 - |
题
我正在寻找类似于Java中的CopyOnWriteSet的东西,这个集合支持 add
, remove
和某些类型的 iterators
多线程。
解决方案
没有我所知道的,最接近的是具有 concurrent_unordered_map
STL容器允许来自多个线程的并发读取访问权限只要你不做并发修改。通常没有必要在添加/删除时进行迭代。
关于提供简单包装类的指导是理智的,我会从下面的代码片段开始,保护你真正需要并发访问的方法,然后提供对基本std :: set的“不安全”访问权限可以选择其他不安全的方法。如果有必要,你可以保护访问以及获取迭代器并将它们放回去,但这很棘手(仍然不如编写自己的锁定集或你自己的完全同步集)。
我在并行模式库上工作,所以我正在使用VS2010 beta的训练版:: mutex也很有效,无论你如何选择这样做,使用lock_guard的RAII模式几乎是必要的:
template <class T>
class synchronized_set
{
//boost::mutex is good here too
critical_section cs;
public:
typedef set<T> std_set_type;
set<T> unsafe_set;
bool try_insert(...)
{
//boost has a lock_guard
lock_guard<critical_section> guard(cs);
}
};
其他提示
为什么不使用共享互斥锁来保护并发访问?务必使用RAII来锁定和解锁互斥锁:
{
Mutex::Lock lock(mutex);
// std::set manipulation goes here
}
其中Mutex :: Lock是一个锁定构造函数中的互斥锁并在析构函数中解锁它的类,而互斥锁是一个由所有线程共享的互斥锁对象。 Mutex只是一个包装类,它隐藏了您正在使用的任何特定操作系统原语。
我一直认为并发和集合行为是正交概念,因此最好将它们放在不同的类中。根据我的经验,尝试线程安全的类本身并不是非常灵活或者非常有用。
您不希望内部锁定,因为您的不变量通常需要对数据结构进行多次操作,而内部锁定只能防止步骤同时发生,而您需要保留不同宏操作的步骤交织。
您还可以查看ACE库,其中包含您可能需要的所有线程安全容器。
我能想到的是使用OpenMP进行并行化,从std中派生一个set类,并在每个批判集操作周围放置一个shell,该操作使用#pragma omp critical来声明该操作至关重要。
Qt的QSet类使用隐式共享(写入语义上的复制)和类似的方法与std :: set,你可以看看它的实现,Qt是lgpl。
线程安全和写入语义上的复制不是一回事。那就是说......
如果你真的在写时复制语义之后,Adobe源库有一个 copy_on_write
模板,将这些语义添加到您使用它实例化的任何内容中。