繁体   English   中英

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

[英]Thread safety of multiple-reader/single-writer class

我正在研究经常阅读但很少编写的集合。

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()的线程是否可能在insert to tmpSet之前观察到swap _mySet发生?

你需要同步,它不是线程安全的。 一般来说,无关紧要,甚至像shared += value;这样简单shared += value; 不是线程安全的。

请看这里关于shared_ptr的线程安全性的例子: boost shared_ptr <XXX>线程是否安全?

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

更新:

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

这是shared_ptr用于实现线程安全的有趣用法。 它是否正常取决于boost::shared_ptr的线程安全保证。 特别是,它是否建立了某种类型的fence或membar,以便保证在指针值的任何修改变为可见之前,构造函数中的所有写入和set insert函数都会发生。

我在智能指针的Boost文档中找不到任何线程安全保证。 这让我感到震惊,因为我确信有一些。 但是快速查看1.47.0的源代码显示没有,并且在线程环境中使用boost::shared_ptr将会失败。 (请有人请指出我缺少的东西。我无法相信boost::shared_ptr忽略了线程。)

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

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

atomic_store(&_my_set,tmpSet);

theSet = atomic_load(&_mySet);

(而不是简单的任务)

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM