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

2021-12-06 00:00:00 multithreading c++ c++11 stdthread

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

How can I check if a std::thread is still running (in a platform independent way)? It lacks a timed_join() method and joinable() is not meant for that.

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

I thought of locking a mutex with a std::lock_guard in the thread and using the try_lock() method of the mutex to determine if it is still locked (the thread is running), but it seems unnecessarily complex to me.

你知道更优雅的方法吗?

Do you know a more elegant method?

更新: 明确地说:我想检查线程是否干净地退出.一个挂起"的线程被视为为此目的而运行.

Update: To be clear: I want to check if the thread cleanly exited or not. A 'hanging' thread is considered running for this purpose.

推荐答案

如果你愿意使用 C++11 std::asyncstd::future 来运行你的任务,然后你可以利用 std::futurewait_for 函数来检查线程是否仍在以这样一种简洁的方式运行:

If you are willing to make use of C++11 std::async and std::future for running your tasks, then you can utilize the wait_for function of std::future to check if the thread is still running in a neat way like this:

#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 来获取未来的对象:

If you must use std::thread then you can use std::promise to get a future object:

#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

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

This is of course because the thread status is checked before the task is finished.

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

But then again, it might be simpler to just do it like others have already mentioned:

#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::thread 一起使用的 std::packaged_task 比使用 std::promise 更简洁的解决方案:

There's also the std::packaged_task for use with std::thread for a cleaner solution than using 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.
}

相关文章