[英]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.