将shared_ptr传递给线程
Passing shared_ptr to thread
我有以下代码:
shared_ptr<A> a;
B b(a);
a.reset(new A());
而在 B 类中,我创建了一个新线程并等待 a "准备就绪":
B(shared_ptr<A> a) {
_a = a;
//create thred here
}
//...
//in thread:
while (_this->_a == NULL) {}
问题是,即使在 a.reset(new A(((; 行被执行之后,在 B 中启动的线程仍然认为 _this->_a 是空的,永远不会离开 while 循环!
我尝试使用 a = make_shared(new A(((;或 a = shared_ptr(new A(((; - 效果仍然相同。我也试图传递一个作为常量引用 - 同样的事情。
最有趣的是,当我使用纯指针并将对该指针的引用传递给类 B 时,一切正常:
A* a;
B b(a);
a = new A();
//...
B(A*& a) {
_a = a;
//create thred here
}
//in thread:
while (_this->_a == NULL) {}
//In this case the loop is finished
我在这里错过了什么?
更新(01.05.2014(:我用这样的代码解决了这个问题:
typedef shared_ptr<ClassA> ClassAPtr;
typedef shared_ptr<ClassB> ClassBPtr;
typedef shared_ptr<ClassC> ClassCPtr;
//...
ClassAPtr a(new ClassA());
ClassBPtr b( new ClassB() );
b->attachA(a);
a->attachB(b);
ClassCPtr c( new ClassC() );
c->attachB(b);
c->attachA(a);
c->run();
b->run();
a->run();
在每个类中,我都有原子变量_running:
atomic<bool> _running;
此外,我在每个线程循环中都有以下同步代码:
while (
_this->_a == NULL || !_this->_a->isRunning()
||
_this->_b == NULL || !_this->_b->isRunning()
)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
您正在将shared_ptr<A>
的副本传递给B
的实例。当您通过调用reset
将新对象分配给a
时,存储在b
中的副本不知道这已经发生了。这就是为什么它永远不会看到更新的原因。
调用 shared_ptr::reset
会使该 shared_ptr
实例放弃托管对象的所有权,这意味着如果该实例恰好是唯一所有者,则递减use_count
并销毁对象。如果它不是唯一的所有者,则管理该对象的其他shared_ptr
将负责管理其生存期。无论哪种情况,您调用reset
的实例现在可以自由地获得您可能已作为参数传递的另一个对象的所有权。在您的情况下,这一切都更简单一些,因为最初没有管理对象,但相同的逻辑适用。存储在 b
中的副本在调用 reset
后不会链接到a
。
假设你的类A
实现了两个成员函数,activate()
和 is_active()
,具有明显的功能。还假设构造 A
的实例会使其处于停用状态,直到您调用 activate()
。然后你可以按如下方式解决这个问题:
auto a = make_shared<A>();
B b(a);
a->activate();
// within the thread
while (!_this->_a->is_active()) {}
即便如此,您仍需要使用一些同步原语来防止数据竞争。例如,如果activate()
设置了一个布尔数据成员,则该成员的类型应该是std::atomic<bool>
或std::atomic_flag
,而不是普通bool
。这同样适用于可能从不同线程读取和写入的任何其他数据成员。
std::shared_ptr
不是线程安全的。您需要使用不同的同步机制。 std::future
是一个可用于等待另一个线程的对象。您可以使用 std::packaged_task
创建一个。
可能发生的情况是,本地副本由共享指针的内部组成。此缓存副本不知道主内存中的更新。指针已更新,但这取决于哪个编译器、哪些优化处于活动状态以及 CPU 体系结构。
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 异常属于C++中的线程还是进程
- C++中的线程安全删除
- C++使用params创建线程函数会导致转换错误
- 类与私有变量的其他类之间的线程安全性
- CoInitialize()在单独的线程上崩溃而不返回
- c++中的线程池
- 线程之间的布尔停止信号
- 为什么std::async使用同一个线程运行函数
- 用于矢量处理的多个线程
- C++为线程工作动态地分割例程
- 在另一个线程中分配唯一ptr的错误