多读者/单作者类的线程安全性

时间:2012-02-07 06:26:14

标签: c++ boost thread-safety

我正在研究经常阅读但很少写的一套。

class A {
  boost::shared_ptr<std::set<int> > _mySet;
public:
  void add(int v) {
    boost::shared_ptr<std::set<int> > tmpSet(new std::set<int>(*_mySet));
    tmpSet->insert(v);  // insert to tmpSet
    _mySet = tmpSet;    // swap _mySet
  }
  void check(int v) {
    boost::shared_ptr<std::set<int> > theSet = _mySet;
    if (theSet->find(v) != theSet->end()) {
      // do something irrelevant
    }
  }
};

在类中,add()仅由一个线程调用,而check()由多个线程调用。 check()并不关心_mySet是否是最新版本。类是线程安全的吗?执行check()的线程是否有可能在swap _mySet之前发现insert to tmpSet

3 个答案:

答案 0 :(得分:2)

您确实需要同步,它不是线程安全的。通常它并不重要,即使像shared += value;这样简单的东西也不是线程安全的。

在这里查看有关shared_ptr的线程安全性的示例:Is boost shared_ptr <XXX> thread safe?

我还会质疑您在add()中的分配/交换以及在shared_ptr中使用check()

更新

我回去并为shared_ptr重新发布dox ...由于shared_ptr的引用计数是线程安全的,因此很可能是特定于线程安全的。但是,由于不使用读/写锁定,您正在做(IMHO)不必要的复杂性。

答案 1 :(得分:2)

这是shared_ptr实现线程安全的一个有趣用法。 是否可以取决于线程安全保障 boost::shared_ptr。特别是,它是否建立了某种形式 fence或membar,这样就可以保证所有的写入 insert的构造函数和set函数在任何函数之前出现 指针值的修改变得可见。

我可以在Boost中找到没有线程安全保证 智能指针的文档。正如我所确定的那样,这让我感到震惊 有一些。但是快速查看1.47.0的来源显示没有, 并且在线程环境中使用boost::shared_ptr会 失败。 (有人可以指出我错过了什么。我不能 相信boost::shared_ptr忽略了线程。)

无论如何,有三种可能性:你不能使用共享指针 在线程环境(似乎就是这种情况)中,共享 指针在线程环境中确保自己的内部一致性, 但是没有建立关于其他对象的排序,或者 共享指针建立完整排序。只有在最后一种情况下才会 你的代码是安全的。在第一种情况下,你需要某种形式的 锁定一切,在第二,你需要某种 fences或membar以确保实际完成必要的写入 在发布新版本之前,他们将在之前看到过 试着读它。

答案 2 :(得分:0)

最终这段代码应该是线程安全的:

atomic_store(&_my_set,tmpSet);

theSet = atomic_load(&_mySet);

(而不是简单的作业)

但我不知道shared_ptr的原子性支持的当前状态。

注意,以无锁方式向shared_ptr添加原子性是真的很难的事情;所以即使实现了原子性,它也可能在互斥锁或用户模式自旋锁上传递,因此有时可能会遇到性能问题

编辑:也许,也应该添加_my_set成员变量的volatile限定符..但我不确定原子操作的语义是否严格要求