使用多线程时,我经常会遇到以下问题:
我有一个对象,比如一个网络接收器(但可能是任何东西)。以及获取数据的函数。现在有时根本没有数据,你想让线程等待获取它的数据。阻塞调用,非常类似于Berkeley套接字和它的派生实现。
原则很简单:
现在当然还有其他方法可以实现这一点。但我通常用C ++ 11实现如下:
Object A
在一个专门用于此任务的单独线程上调用对象B中的函数。Object B
使用std::condition_variable
构造来阻止线程,直到实际获取数据。 Object A
将数据放入队列中,由主线程读出。现在我的实际问题出现在object B
的破坏上,如果它必须在object A
之前被破坏(在阻塞调用中返回nullptr或类似的东西)。我真的不知道如何有效地结束object B
。
主要问题是object B
不知道线程,并且线程只能有一个句柄,位于object A
内。
示例:
一些代码来说明我的问题。
说我在对象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;
我们仍然存在这样的问题:析构函数必须在指示的Point X
处等待,直到所有其他线程都收到通知,并返回null。
现在我可以使用原子计数器,更多std::condition_variable
和互斥量来烹饪。但我有一种感觉,必须有一个更优雅和可靠的解决方案来解决这个问题:)。由于此解决方案需要在每个getData
调用中通知object B
的整个生命周期。
注意:我使用C ++ 11,所以我用它来说明一切。而且我希望用它来解决它。虽然这当然是一个更普遍的并发问题。
答案 0 :(得分:2)
如何使用std::shared_ptr
管理对象B
并使用std::weak_ptr
将指针存储在A
?
每次A
想要访问权限时,效率会稍微低一些,但它本身暂时需要std::shared_ptr
到std::weak_ptr::lock()
,但您可以确定没有比赛条件了。
答案 1 :(得分:1)
我的实际问题出现在对象B的破坏上,如果必须的话 在对象A之前被破坏
这里我描述了另一种处理删除可能在其中运行的线程的对象实例的方法。嵌入式系统行为可能与您的设计有太大不同......但也许它可以激发一种新的方式来看待您的挑战。
总结:使用废纸篓和看门人。
什么时候去除&#39;一个可能有其他线程工作的对象
1) copy pointer-to-object to the 'waste-basket' fifo
A* a; waste_basket.push_back(a);
2) copy pointer-to-replacement-object to replace pointer-to-object
A* t = new(replacementObject);
a = t;
Use low priority janitor thread to inspect waste-basket periodically
and delete any resident older than max duration. Max duratin ensures
any other thread activity has completed.
废纸篓中的n秒,防止删除对象 而线程仍在使用它。 (您的持续时间可能会有所不同。)
在我工作的嵌入式系统中,有28个被动(没有 内部线程)多态表中的对象实例(卡片中的 货架),以及在任何给定时间可能有的大约10多个线程 通过其中一个卡实例与hw进行交互。
即使操作员(在ui线程上)可能会命令删除实例 j(货架中的第j张卡),对象可以不被删除 直到当前正在执行的所有线程完成其当前活动。
部分由于每种方法的简短性质(<25 ms),我们做到了 不使用计数,也不使用信号量来确定未访问的实例 州。相反,我们分两步完成了删除过渡, 并推迟了卡的实际删除。
步骤1)将桌面条目架[j]复制到“废纸篓”中。 fifo list,
步骤2)将表格条目[j]替换为空插槽&#39; 实例指针,所有架构使用线程都知道如何 多态地使用(好像它只是另一张牌)。
这两个步骤使逻辑删除瞬间显示 用户和线程。但是删除什么时候会发生呢?
所有现有主题都需要在完成后离开实例。他们的活动。但这可能会持续多久?
我们提出的衍生要求(基于设计的其他方面)是任何线程&#39;工作&#39;在一个对象实例中,应该在&lt; 25毫秒从务实的角度来说,大多数都完成得更快,没有更长的时间。
因此,对于这种嵌入式系统和便利性,团队决定废弃的篮子“保持”#39;持续时间将> = 1秒。
请注意,当被移除的卡片存放在废纸篓中时,没有 其他线程可以访问它,也不会在同一个对象中启动另一个活动。当他们找到一个空位时,其他线程被误导了。卡在架子上。该卡在逻辑上已经消失,如果尚未从内存中删除的话。
为完成此设计,我们添加了一个低优先级的清洁工任务,定期处理废纸篓清单。看门人检查了实例到达废纸篓的到达时间,并且在队列中至少1秒后才删除任何卡片。