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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9094422/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 12:17:22  来源:igfitidea点击:

How to check if a std::thread is still running?

c++multithreadingc++11stdthread

提问by kispaljr

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

如何检查 astd::thread是否仍在运行(以独立于平台的方式)?它缺乏一种timed_join()方法,joinable()并不意味着它。

I thought of locking a mutex with a std::lock_guardin 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.

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

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.

更新:要清楚:我想检查线程是否干净地退出。一个“挂起”的线程被认为是为此目的而运行的。

回答by Snps

If you are willing to make use of C++11 std::asyncand std::futurefor running your tasks, then you can utilize the wait_forfunction of std::futureto check if the thread is still running in a neat way like this:

如果您愿意使用 C++11std::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.
}

If you must use std::threadthen you can use std::promiseto get a future object:

如果必须使用,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.
}

Both of these examples will output:

这两个示例都将输出:

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.
}

Edit:

编辑:

There's also the std::packaged_taskfor use with std::threadfor a cleaner solution than using std::promise:

还有一个std::packaged_taskfor use withstd::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.
}

回答by Some programmer dude

An easy solution is to have a boolean variable that the thread sets to true on regular intervals, and that is checked and set to false by the thread wanting to know the status. If the variable is false for to long then the thread is no longer considered active.

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

A more thread-safe way is to have a counter that is increased by the child thread, and the main thread compares the counter to a stored value and if the same after too long time then the child thread is considered not active.

一个更线程安全的方法是有一个由子线程增加的计数器,主线程将计数器与存储的值进行比较,如果太长时间后相同,则认为子线程不活动。

Note however, there is no way in C++11 to actually kill or remove a thread that has hanged.

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

EditHow to check if a thread has cleanly exited or not: Basically the same technique as described in the first paragraph; Have a boolean variable initialized to false. The last thing the child thread does is set it to true. The main thread can then check that variable, and if true do a join on the child thread without much (if any) blocking.

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

Edit2If the thread exits due to an exception, then have two thread "main" functions: The first one have a try-catchinside which it calls the second "real" main thread function. This first main function sets the "have_exited" variable. Something like this:

Edit2如果线程因异常退出,则有两个线程“主”函数:第一个有try-catch在其中调用第二个“真实”主线程函数。第一个主函数设置“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;
}

回答by Evgeny Karpov

This simple mechanism you can use for detecting finishing of a thread without blocking in join method.

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

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

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

回答by Nathan Fox

Create a mutex that the running thread and the calling thread both have access to. When the running thread starts it locks the mutex, and when it ends it unlocks the mutex. To check if the thread is still running, the calling thread calls mutex.try_lock(). The return value of that is the status of the thread. (Just make sure to unlock the mutex if the try_lock worked)

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

One small problem with this, mutex.try_lock() will return false between the time the thread is created, and when it locks the mutex, but this can be avoided using a slightly more complex method.

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

回答by Michal Turlik

You can always check if the thread's id is different than std::thread::id() default constructed. A Running thread has always a genuine associated id. Try to avoid too much fancy stuff :)

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

回答by Lightness Races in Orbit

Surely have a mutex-wrapped variable initialised to false, that the thread sets to trueas the last thing it does before exiting. Is that atomic enough for your needs?

肯定有一个互斥体包装的变量初始化为false,线程设置true为它在退出之前所做的最后一件事。这足够满足您的需求吗?