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

C++MultithreadingC++11Stdthread

C++ Problem Overview


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.

C++ Solutions


Solution 1 - C++

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

Solution 2 - C++

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.

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.

Edit How 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.

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

std::atomic<bool> thread_done = false;

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

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

    thread_done = true;

    return res;
}

Solution 3 - C++

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 :)

Solution 4 - C++

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

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

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

Solution 5 - C++

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)

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.

Solution 6 - C++

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

Solution 7 - C++

I checked both systems: -Using thread+atomic: take 9738 milliseconds -Using future+async: take 7746 milliseconds Not threads: 56000milliseconds Using a Core-I7 6 cores laptop

My code creates 4000 threads, but no more than 12 running every time.

Here is the code:

#include <iostream>
#include <thread>
#include <future>
#include <chrono>
#include <mutex>          // std::mutex
#include <atomic>
#include <chrono>


#pragma warning(disable:4996)
#pragma warning(disable:6031)
#pragma warning(disable:6387)//strout
#pragma warning(disable:26451)

using namespace std;
const bool FLAG_IMPRIME = false;
const int MAX_THREADS = 12;


mutex mtx;           // mutex for critical section
atomic <bool> th_end[MAX_THREADS];
atomic <int> tareas_acabadas;

typedef std::chrono::high_resolution_clock t_clock; //SOLO EN WINDOWS
std::chrono::time_point<t_clock> start_time, stop_time; char null_char;
void timer(const char* title = 0, int data_size = 1) { stop_time = t_clock::now(); double us = (double)chrono::duration_cast<chrono::microseconds>(stop_time - start_time).count();	if (title) printf("%s time = %7lgms = %7lg MOPs\n", title, (double)us * 1e-3, (double)data_size / us); start_time = t_clock::now(); }



class c_trim
{
	char line[200];
	thread th[MAX_THREADS];
	double th_result[MAX_THREADS];
	int th_index;
	double milliseconds_commanded;
	void hilo(int hindex,int milliseconds, double& milliseconds2)
	{
		sprintf(line, "%i:%ia ",hindex, milliseconds); imprime(line);
		this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
		milliseconds2 = milliseconds * 1000;
		sprintf(line, "%i:%ib ", hindex, milliseconds); imprime(line);
		tareas_acabadas++;  th_end[hindex] = true;
	}
	int wait_first();
	void imprime(char* str) { if (FLAG_IMPRIME) { mtx.lock(); cout << str; mtx.unlock(); } }

public:
	void lanzatareas();


	vector <future<void>> futures;
	int wait_first_future();
	void lanzatareas_future();//usa future
};

int main()
{
	c_trim trim;
	timer();
	trim.lanzatareas();
	cout << endl;
	timer("4000 tareas using THREAD+ATOMIC:", 4000);
	trim.lanzatareas_future();
	cout << endl;
	timer("4000 tareas using FUTURE:", 4000);
	cout << endl << "Tareas acabadas:" << tareas_acabadas << endl;
	cout << "=== END ===\n"; (void)getchar();
}

void c_trim::lanzatareas()
{
	th_index = 0;
	tareas_acabadas = 0;
	milliseconds_commanded = 0;
	double *timeout=new double[MAX_THREADS];
	int i;
	for (i = 0; i < MAX_THREADS; i++)
	{
		th_end[i] = true;
		th_result[i] = timeout[i] = -1;
	}


	for (i = 0; i < 4000; i++)
	{
		int milliseconds = 5 + (i % 10) * 2;
		{
			int j = wait_first();
			if (th[j].joinable())
			{
				th[j].join();
				th_result[j] = timeout[j];
			}
			milliseconds_commanded += milliseconds;
			th_end[j] = false;
			th[j] = thread(&c_trim::hilo, this, j, milliseconds, std::ref(timeout[j]));
		}
	}
	for (int j = 0; j < MAX_THREADS; j++)
		if (th[j].joinable())
		{
			th[j].join();
			th_result[j] = timeout[j];
		}

	delete[] timeout;
	cout <<endl<< "Milliseconds commanded to wait=" << milliseconds_commanded << endl;
}

void c_trim::lanzatareas_future()
{
	futures.clear();
	futures.resize(MAX_THREADS);

	tareas_acabadas = 0;
	milliseconds_commanded = 0;
	double* timeout = new double[MAX_THREADS];
	int i;
	for (i = 0; i < MAX_THREADS; i++)
	{
		th_result[i] = timeout[i] = -1;
	}


	for (i = 0; i < 4000; i++)
	{
		int milliseconds = 5 + (i % 10) * 2;
		{
			int j;
			if (i < MAX_THREADS) j = i;
			else
			{
				j = wait_first_future();
				futures[j].get();
				th_result[j] = timeout[j];
			}
			milliseconds_commanded += milliseconds;
			futures[j] = std::async(std::launch::async, &c_trim::hilo, this, j, milliseconds, std::ref(timeout[j]));
		}
	}
	//Last MAX_THREADS:
	for (int j = 0; j < MAX_THREADS; j++)
	{
		futures[j].get();
		th_result[j] = timeout[j];
	}

	delete[] timeout;
	cout << endl << "Milliseconds commanded to wait=" << milliseconds_commanded << endl;
}

int c_trim::wait_first()
{
	int i;
	while (1)
		for (i = 0; i < MAX_THREADS; i++)
		{
			if (th_end[i] == true)
			{
				return i;
			}
		}
}



//Espera que acabe algun future y da su index
int c_trim::wait_first_future()
{
	int i;
	std::future_status status;
	while (1)
		for (i = 0; i < MAX_THREADS; i++)
		{
			status = futures[i].wait_for(0ms);
			if (status == std::future_status::ready)
				return i;
		}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkispaljrView Question on Stackoverflow
Solution 1 - C++Felix GlasView Answer on Stackoverflow
Solution 2 - C++Some programmer dudeView Answer on Stackoverflow
Solution 3 - C++Michal TurlikView Answer on Stackoverflow
Solution 4 - C++Evgeny KarpovView Answer on Stackoverflow
Solution 5 - C++Nathan FoxView Answer on Stackoverflow
Solution 6 - C++Lightness Races in OrbitView Answer on Stackoverflow
Solution 7 - C++mathengineerView Answer on Stackoverflow