我正在寻找类似于 Java 中的 CopyOnWriteSet 的东西,一个支持 的集合add
,remove
以及iterators
来自多个线程的某种类型。
7 回答
我不知道,最接近的是线程构建块,它有concurrent_unordered_map
只要您不进行并发修改,STL 容器就允许从多个线程进行并发读取访问。通常在添加/删除时不需要迭代。
关于提供简单包装类的指导是明智的,我将从下面的代码片段开始保护您真正需要并发访问的方法,然后提供对基本 std::set 的“不安全”访问,以便人们可以选择加入其他不安全的方法。如有必要,您还可以保护获取迭代器并将其放回的访问,但这很棘手(仍然比编写自己的无锁集或自己的完全同步集要少)。
我在并行模式库上工作,所以我使用 VS2010 beta boost::mutex 中的 critical_section 也很有效,而且无论您如何选择执行此操作,几乎都需要使用 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 派生一个集合类,并在每个关键集合操作周围放置一个外壳,使用 #pragma omp critical 声明该操作是关键的。
Qt的QSet类使用隐式共享(copy on write语义)和std::set类似的方法,可以看它的实现,Qt是lgpl。
线程安全和写时复制语义不是一回事。话虽如此...
如果您真的很喜欢写时复制语义,Adobe 源库有一个copy_on_write
模板,可以将这些语义添加到您使用的任何实例中。