我正在研究经常阅读但很少写的一套。
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
?
答案 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限定符..但我不确定原子操作的语义是否严格要求