我有一个名为 TThreadpool
的类,它包含 std::vector<std::thread>>
类型的成员池,具有以下析构函数:
~TThreadpool() {
for (size_t i = 0; i < pool.size(); i++) {
assert(pool[i].joinable());
pool[i].join();
}
}
我相信,当调用析构函数时,所有线程都在等待单个条件变量(使用始终为假谓词控制的虚假唤醒(,并且可连接输出为 true。
运行线程的简化示例是:
void my_thread() {
std::unique_lock<std::mutex> lg(mutex);
while (true) {
my_cond_variable.wait(lg, [] {
return false;
});
# do some work and possibly break, but never comes farther then wait
# so this probably should not matter
}
}
为了检查正在运行的线程,我正在启动top -H
.在程序开始时,TThreadpool
本身所在的线程有 pool.size()
个线程 + 1 个线程。令我惊讶的是,加入这些活动线程并不会将它们从 top 给出的线程列表中删除。这是预期行为吗?
(最初,我的程序有点不同 - 我使用qt制作了一个简单的UI应用程序,它使用在UI线程中运行的线程池和由线程池控制的其他线程,并且在关闭UI窗口时调用了线程的加入,但是QtCreator说我的应用程序在我关闭窗口后仍然有效,要求我关闭它崩溃。这让我检查了线程的状态,结果发现它与 qt 无关。虽然我添加这个以防万一我错过了 qt 的一些明显细节(。
过了一会儿,我尝试不断言可连接,而是打印它,并发现 Threadpool 析构函数中的循环从未比第一次连接更进一步 - 我没想到也无法解释的行为
join()
不会对子线程执行任何操作 - 它所做的只是阻塞,直到子线程退出。 它只对调用线程有影响(即通过阻止其进度(。 子线程可以根据需要继续运行(尽管通常您希望它快速退出,以便调用join()
线程不会长时间被阻塞 - 但这取决于您来实现(令我惊讶的是,加入这些活动线程并不会将它们从 top 提供的线程列表中删除。这是预期行为吗?
这表明线程仍在运行。在线程上调用 join()
不会对该正在运行的线程产生任何影响;只是调用线程 等待被调用的线程退出。
发现线程池析构函数中的循环从未比第一次连接更进一步
这意味着第一个线程尚未完成。因此,其他线程也没有加入(即使它们已退出(。
但是,如果线程函数正确实现,则第一个线程(以及池中的所有其他线程(最终应完成并 join()
调用应该返回(假设池中的线程应该退出 - 但这通常不需要为 true。 根据应用程序的不同,您也可以简单地使线程永久运行(。
因此,似乎存在某种死锁或等待某些资源阻止一个或多个线程。因此,您需要通过调试器运行。 赫尔格林德将非常有用。
您还可以尝试减少线程数(例如 2 个(,看看问题是否变得可重现/明显,然后您可以增加线程。