如何等待分离的线程在C ++中完成?
我不关心退出状态,我只是想知道线程是否已经完成。
我正在尝试围绕异步的第三方工具提供同步包装器。问题是涉及回调的奇怪的竞争状态崩溃。进展如下:
我想将其包装在一个提供阻塞调用的机制中。到目前为止,我有:
class Wait {
public:
void callback() {
pthread_mutex_lock(&m_mutex);
m_done = true;
pthread_cond_broadcast(&m_cond);
pthread_mutex_unlock(&m_mutex);
}
void wait() {
pthread_mutex_lock(&m_mutex);
while (!m_done) {
pthread_cond_wait(&m_cond, &m_mutex);
}
pthread_mutex_unlock(&m_mutex);
}
private:
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
bool m_done;
};
// elsewhere...
Wait waiter;
thirdparty_utility(&waiter);
waiter.wait();
据我所知,这应该有效,而且通常会有效,但有时它会崩溃。据我所知,我可以从核心文件中确定问题是:
我尝试了很多不同的机制来尝试解决这个问题,但没有一个能解决问题。我仍然偶尔会看到崩溃。
编辑:更多详情:
这是大规模多线程应用程序的一部分,因此创建静态Wait是不切实际的。
我运行了一个测试,在堆上创建Wait,故意泄漏内存(即Wait对象永远不会被释放),这导致没有崩溃。所以我确定这是等待过早释放的问题。
我在sleep(5)
解锁后尝试使用wait
进行测试,但也没有发生崩溃。我讨厌依靠这样的kludge。
编辑:ThirdParty详细信息:
我一开始并不认为这是相关的,但我想的越多,我认为这就是真正的问题:
我提到的第三方内容,以及为什么我无法控制线程:这是使用CORBA。
因此,CORBA可能会持续超过预期对我的对象的引用。
答案 0 :(得分:3)
是的,我相信你所描述的正在发生(解除分配的竞争条件)。解决这个问题的一个简单方法是创建一个静态的Wait实例,一个不会被破坏的实例。只要您不需要同时拥有多个服务员,这将有效。
您还将永久使用该内存,它不会取消分配。但它看起来并不太糟糕。
主要问题是难以在线程之间协调线程通信结构的生命周期:当它可以安全销毁时,你总是需要至少一个剩余的通信结构来进行通信(至少在没有垃圾收集的语言中,比如C ++ )。
修改强>: 有关使用全局互斥锁引用计数的一些想法,请参阅注释。
答案 1 :(得分:0)
据我所知,如果线程已完成运行(即没有pthread_
函数),则没有直接询问线程的可移植方式。你正在做什么是正确的做法,至少就你有信号的条件而言。如果你看到崩溃,你肯定是因为Wait
对象在创建它的线程退出时被释放(而不是某些其他微妙的锁定问题 - 太常见了) ,问题是您需要通过从执行通知的线程以外的线程进行管理来确保Wait
不被解除分配。将它放在全局内存中或动态分配它并与该线程共享。最简单的就是没有线程等待自己的内存等待,让线程做等待拥有它。
答案 2 :(得分:0)
您是否正确初始化并销毁互斥锁和条件var?
Wait::Wait()
{
pthread_mutex_init(&m_mutex, NULL);
pthread_cond_init(&m_cond, NULL);
m_done = false;
}
Wait::~Wait()
{
assert(m_done);
pthread_mutex_destroy(&m_mutex);
pthread_cond_destroy(&m_cond);
}
确保你没有过早地破坏Wait
对象 - 如果它在一个线程中被破坏而另一个线程仍然需要它,你将获得一个可能导致段错误的竞争条件。我建议将它作为一个全局静态变量,它在程序初始化时构建(在main()
之前)并在程序退出时被销毁。
答案 3 :(得分:0)
如果您的假设是正确的,那么第三方模块似乎是错误的,您需要提出某种方法来使您的应用程序正常工作。
静态Wait
不可行。如果Wait
池(它甚至可能按需增长)怎么样?您是使用线程池运行的应用程序吗?
虽然第三方模块仍然在使用它时,仍然有可能重复使用相同的Wait
。但是你可以通过适当排队游泳池中空缺的等待来最小化这种机会。
免责声明:我绝不是线程安全方面的专家,所以请将此帖作为外行人的建议。