线程安全的 C++ std::set 支持从多个线程添加、删除和迭代器
Posted
技术标签:
【中文标题】线程安全的 C++ std::set 支持从多个线程添加、删除和迭代器【英文标题】:Thread safe C++ std::set that supports add, remove and iterators from multple threads 【发布时间】:2009-09-10 11:22:15 【问题描述】:我正在寻找类似于 Java 中的 CopyOnWriteSet 的东西,该集合支持来自多个线程的add
、remove
和某种类型的iterators
。
【问题讨论】:
【参考方案1】:据我所知没有一个,最接近的是线程构建块,它有concurrent_unordered_map
只要您不进行并发修改,STL 容器就允许concurrent read access from multiple threads。通常在添加/删除时不需要迭代。
关于提供简单包装类的指导是明智的,我将从下面的代码 sn-p 开始,保护您真正需要并发访问的方法,然后提供对基本 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);
;
【讨论】:
【参考方案2】:为什么不只使用共享互斥锁来保护并发访问?请务必使用 RAII 锁定和解锁互斥锁:
Mutex::Lock lock(mutex);
// std::set manipulation goes here
其中Mutex::Lock是在构造函数中锁定互斥体,在析构函数中解锁互斥体的类,互斥体是所有线程共享的互斥体对象。 Mutex 只是一个封装类,它隐藏了您正在使用的任何特定操作系统原语。
我一直认为并发和集合行为是正交的概念,所以最好将它们放在单独的类中。根据我的经验,尝试自身线程安全的类不是很灵活,也不是很有用。
【讨论】:
【参考方案3】:您不需要内部锁定,因为您的不变量通常需要对数据结构进行多次操作,而内部锁定只能防止这些步骤同时发生,而您需要保持来自不同宏操作的步骤交错。
【讨论】:
【参考方案4】:您还可以查看 ACE 库,其中包含您可能需要的所有线程安全容器。
【讨论】:
【参考方案5】:我能想到的就是使用 OpenMP 进行并行化,从 std 派生一个集合类,并在每个关键集合操作周围放置一个外壳,使用 #pragma omp critical 声明该操作是关键的。
【讨论】:
我认为您不应该从标准容器派生。他们没有虚拟析构函数。在这种情况下,组合会更好。【参考方案6】:Qt的QSet类使用隐式共享(copy on write语义)和std::set类似的方法,你可以看看它的实现,Qt是lgpl。
【讨论】:
【参考方案7】:线程安全和写时复制语义不是一回事。话说……
如果您真的喜欢写时复制语义,Adobe 源库有一个 copy_on_write
模板,可以将这些语义添加到您使用的任何实例中。
【讨论】:
以上是关于线程安全的 C++ std::set 支持从多个线程添加、删除和迭代器的主要内容,如果未能解决你的问题,请参考以下文章
C++并发编程----实现线无锁线程安全的数据结构(《C++ Concurrency in Action》 读书笔记)