c++multithreadingc++11stdthread

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


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.

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.


Solution

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

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

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