线程安全的 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 的东西,该集合支持来自多个线程的addremove 和某种类型的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 支持从多个线程添加、删除和迭代器的主要内容,如果未能解决你的问题,请参考以下文章

linux C++去重排序(std::set容器)

linux C++去重排序(std::set容器)

C++并发编程----实现线无锁线程安全的数据结构(《C++ Concurrency in Action》 读书笔记)

C++ std::set operator <= find失效 erase失效 解决方案

自定义内存池(C++需要掌握)

C++ STL set和multiset的使用