程序终止前加入线程

时间:2016-07-21 19:08:38

标签: c++ multithreading

我有一个在执行应用程序时收集的线程向量。为了避免一些讨厌的行为,我试图确保在主线程退出时完成每个线程。我试图在终止事件时在向量中的每个线程上调用std::thread::join,但是如果最近的线程没有完成其工作并且即使在它之后也不会阻止它,它似乎会卡住应该。重要的是要注意ThingMaker::CreateThing从一系列视频文件中读取帧并将它们全部写入一个视频,因此我知道线程应该在比视频片段长度更短的时间内完成其工作。创建

std::vector<std::thread> threadList;
while (!done)
{
    switch (triggerEvent)
    {
        case 'h': // Spawn new thread to make a thing "in the background"
        {
            ThingMaker next_thing = new ThingMaker();
            threadList.push_back(std::thread(&ThingMaker::CreateThing, next_thing));
            next_thing = NULL;
            break;
        }
        case 't': // Terminate the application
        {
            std::vector<std::thread>::iterator threads;
            for (threads = threadList.begin(); threads != threadList.end(); ++threads)
                threads->join();
            done = true;
            break;
        }
        default: break;
    }
}

如果我发送了&#39;在最近的线程完成制作视频片段并因此完成之前,threads->join()永远阻止。但是,如果我等待创建所有视频​​剪辑,应用程序将终止。根据我的理解,它应该只是等待线程完成它的工作,然后让主线程继续 - 这是一个误解吗?

4 个答案:

答案 0 :(得分:3)

您的代码中存在两个问题:

  • 活动线程上的join()将等待线程完成,然后继续执行任何操作。因此,如果您没有机制告诉您的线程停止(例如共享原子变量),您将永远等待。

  • 您的threadlist向量 在while循环中,因此它是每个出现时的新列表。你推入它的线程会发生什么?它被破坏了,并且在没有调用join()时,它会terminate()你的程序。

答案 1 :(得分:3)

有两种可能性:

  1. 线程尚未完成。您可以在代码中添加日志记录,也可以使用调试器查看是否属于这种情况。

  2. 调用join的线程拥有一些阻止其他线程完成的锁定。调用join等待线程完成并且无法安全地调用,除非您完全确定调用join的线程不会保留其他线程可能需要获取的锁才能完成。 (仔细查看调用堆栈,调用join以查看这是否可行。)

答案 2 :(得分:1)

使用std::thread,您必须确保每个线程无法加入(通常意味着调用.join()),只需一次。显然,对.join()的调用将等待该线程完成。启动调试会话,看看每个线程正在做什么。

答案 3 :(得分:0)

您加入后,您显示的代码(仍然非常不完整,因此我们只是在猜测)并不会从向量中删除thread个对象。这意味着您将在下一次循环中尝试重新加入已加入的线程。尝试加入不可连接的线程具有未定义的行为。它可以永远阻止(因为没有这样的线程所以它永远不会被连接)。

你应该:

  • 只尝试连接可连接的线程:

    case 't': // Terminate the application
    {
        for (auto& t : threadList)
        if (t.joinable())
            t.join();
        done = true;
        break;
    }
    
  • 或在加入后从列表中删除主题:

    case 't': // Terminate the application
    {
        for (auto& t : threadList)
            t.join();
        threadList.clear();
        done = true;
        break;
    }