正在连接的等待条件变量的线程会发生什么情况?



我有一个名为 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 个(,看看问题是否变得可重现/明显,然后您可以增加线程。

最新更新