在使用多线程时,我经常遇到以下问题:
我有一个对象,比如一个网络接收器(但也可能是其他任何东西),还有一个获取数据的函数。现在有时候没有数据可用,你希望让线程等待获取它的数据。这是一个阻塞调用,非常类似于伯克利套接字及其衍生实现所使用的方式。
原理很简单:
当然,还有其他实现方式。但我的通常实现方式是使用C++11,具体如下:
Object A
在一个专门负责此任务的单独线程中调用Object B
中的函数。Object B
使用std::condition_variable
构造来阻塞线程,直到实际获取数据。Object A
将数据放入队列中,由主线程读取。
现在,如果必须在object A
之前销毁object B
(在阻塞调用上返回nullptr或类似内容),那么我实际上遇到的问题就出现了。我真的不知道如何有效地包装object B
。
主要问题是object B
不知道线程的存在,而线程只能有一个句柄,这个句柄在object A
中。
示例:
下面是一些代码来说明我的问题。
假设我在Object B
中有以下函数:
data* getData
{
std::unique_lock<std::mutex>l_newDataWaiterLock(m_newDataWaiterMutex);
m_newDataWaiter.wait(l_newDataMutex);
if(!running)
return nullptr
else
return data;
}
还有这个析构函数:
~ObjectB()
{
m_running = false;
m_newDataWaiter.notifyAll();
//Point X
}
有以下这些成员变量:
std::condition_variable m_newDataWaiter;
std::atomic<bool> m_running;
我们仍然存在一个问题,即析构函数将不得不在指定的"X点"等待,直到所有其他线程收到通知并返回空值。
现在,我可以使用原子计数器、更多的std::condition_variable和互斥锁来解决这个问题。但是,我有一种感觉,必须有一种更优雅和可靠的解决方案 : )。由于这个解决方案需要在整个B对象的生命周期中的每个getData调用中发出通知。
注意:我正在使用C++11,所以我已经用它来说明一切。我希望使用它来解决这个问题。虽然这当然是一个更普遍的并发问题。
Object B
来指示它即将被销毁。或者我理解错了吗? - laurisvrstd::weak_ptr
的美妙之处:它不会阻止所引用的对象被销毁。只有在您(暂时)拥有一个std::shared_ptr
来放置数据时,才会防止其被销毁。只需使用if( const auto sp = wp.lock() ) { sp->insert(data); }
检查结果即可。整个生命周期管理很难在没有看到整个代码的情况下进行判断,但可以试试! - Daniel Frey