如何检查std :: thread是否仍在运行?

时间:2012-02-01 10:41:20

标签: c++ multithreading c++11 stdthread

如何检查std::thread是否仍在运行(以独立于平台的方式)? 它缺少timed_join()方法,joinable()不适用于此。

我想在线程中使用std::lock_guard锁定互斥锁并使用互斥锁的try_lock()方法来确定它是否仍然被锁定(线程正在运行),但它似乎不必要地复杂对我来说。

你知道更优雅的方法吗?

更新:要明确:我想检查线程是否干净地退出。一个'悬挂'线程被认为是为了这个目的而运行。

6 个答案:

答案 0 :(得分:91)

如果您愿意使用C ++ 11 std::asyncstd::future来运行任务,那么您可以使用wait_for std::future函数来检查如果线程仍然以这样一个整洁的方式运行:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    /* Run some task on new thread. The launch policy std::launch::async
       makes sure that the task is run asynchronously on a new thread. */
    auto future = std::async(std::launch::async, [] {
        std::this_thread::sleep_for(3s);
        return 8;
    });

    // Use wait_for() with zero milliseconds to check thread status.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    auto result = future.get(); // Get result.
}

如果您必须使用std::thread,则可以使用std::promise来获取未来的对象:

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a promise and get its future.
    std::promise<bool> p;
    auto future = p.get_future();

    // Run some task on a new thread.
    std::thread t([&p] {
        std::this_thread::sleep_for(3s);
        p.set_value(true); // Is done atomically.
    });

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

这两个例子都将输出:

Thread still running

这当然是因为在任务完成之前检查了线程状态。

但话说回来,就像其他人已经提到的那样做起来可能更简单:

#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::atomic<bool> done(false); // Use an atomic flag.

    /* Run some task on a new thread.
       Make sure to set the done flag to true when finished. */
    std::thread t([&done] {
        std::this_thread::sleep_for(3s);
        done = true;
    });

    // Print status.
    if (done) {
        std::cout << "Thread finished" << std::endl;
    } else {
        std::cout << "Thread still running" << std::endl;
    }

    t.join(); // Join thread.
}

修改

还有std::packaged_taskstd::thread一起用于更清洁的解决方案,而不是使用std::promise

#include <future>
#include <thread>
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    // Create a packaged_task using some task and get its future.
    std::packaged_task<void()> task([] {
        std::this_thread::sleep_for(3s);
    });
    auto future = task.get_future();

    // Run task on new thread.
    std::thread t(std::move(task));

    // Get thread status using wait_for as before.
    auto status = future.wait_for(0ms);

    // Print status.
    if (status == std::future_status::ready) {
        // ...
    }

    t.join(); // Join thread.
}

答案 1 :(得分:6)

一个简单的解决方案是使用一个布尔变量,线程在定期的时间间隔内设置为true,并且由想知道状态的线程检查并设置为false。如果变量为false,则该线程不再被视为活动状态。

更加线程安全的方法是让子线程增加一个计数器,并且主线程将计数器与存储值进行比较,如果经过太长时间后相同,那么子线程被认为是不活动的。

但是请注意,C ++ 11中没有办法实际杀死或删除已挂起的线程。

编辑如何检查线程是否已完全退出:基本上与第一段中描述的技术相同;将布尔变量初始化为false。子线程执行的最后一件事是将其设置为true。然后主线程可以检查该变量,如果为true则在子线程上进行连接而没有太多(如果有的话)阻塞。

Edit2 如果线程因异常退出,则有两个线程“主”函数:第一个函数在其中调用try - catch第二个“真正的”主线程功能。第一个main函数设置“have_exited”变量。像这样:

bool thread_done = false;

void *thread_function(void *arg)
{
    void *res = nullptr;

    try
    {
        res = real_thread_function(arg);
    }
    catch (...)
    {
    }

    thread_done = true;

    return res;
}

答案 2 :(得分:3)

这个简单的机制可用于检测线程的完成而不会在连接方法中阻塞。

std::thread thread([&thread]() {
    sleep(3);
    thread.detach();
});

while(thread.joinable())
    sleep(1);

答案 3 :(得分:1)

创建一个正在运行的线程和调用线程都可以访问的互斥锁。当正在运行的线程启动时,它会锁定互斥锁,当它结束时,它会解锁互斥锁。要检查线程是否仍在运行,调用线程将调用mutex.try_lock()。返回值是线程的状态。 (如果try_lock有效,请确保解锁互斥锁)

这个问题的一个小问题,mutex.try_lock()将在创建线程的时间和锁定互斥锁之间返回false,但是使用稍微复杂的方法可以避免这种情况。

答案 4 :(得分:0)

肯定有一个互斥锁包变量初始化为false,该线程设置为true,作为它退出前的最后一件事。这是否足以满足您的需求?

答案 5 :(得分:0)

您始终可以检查线程的ID是否与默认构造的std :: thread :: id()不同。 正在运行的线程始终具有真正的关联ID。 尽量避免花哨的东西:)