8

To my surprise, a C++11 std::thread object that has finished executing, but has not yet been joined is still considered an active thread of execution. This is illustrated in the following code example (built on Xubuntu 13.03 with g++ 4.7.3). Does anyone know if the C++11 standard provides a means to detect if a std::thread object is still actively running code?

#include <thread>
#include <chrono>
#include <iostream>
#include <pthread.h>
#include <functional>
int main() {
    auto lambdaThread = std::thread([](){std::cout<<"Excuting lambda thread"<<std::endl;});
    std::this_thread::sleep_for(std::chrono::milliseconds(250));
    if(lambdaThread.joinable()) {
        std::cout<<"Lambda thread has exited but is still joinable"<<std::endl;
        lambdaThread.join();
    }
    return 0;
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Gearoid Murphy
  • 11,834
  • 17
  • 68
  • 86
  • possible duplicate of [C++11 safely join a thread without using a try / catch block](http://stackoverflow.com/questions/15994650/c11-safely-join-a-thread-without-using-a-try-catch-block) – Nicol Bolas Aug 05 '13 at 17:59
  • 3
    `joinable` has nothing to do with whether the thread is executing. – Nicol Bolas Aug 05 '13 at 18:04
  • 2
    This linked answer is not relevant, I wanted to know how to check if a thread is still active, not when it's safe to join, bamboon's answer addresses this perfectly – Gearoid Murphy Aug 05 '13 at 19:11

3 Answers3

8

No, I don't think that this is possible. I would also try to think about your design and if such a check is really necessary, maybe you are looking for something like the interruptible threads from boost.

However, you can use std::async - which I would do anyway - and then rely on the features std::future provides you.

Namely, you can call std::future::wait_for with something like std::chrono::seconds(0). This gives you a zero-cost check and enables you to compare the std::future_status returned by wait_for.

auto f = std::async(foo);
...
auto status = f.wait_for(std::chrono::seconds(0));
if(status == std::future_status::timeout) {
    // still computing
}
else if(status == std::future_status::ready) {
    // finished computing
}
else {
    // There is still std::future_status::defered
}
Stephan Dollberg
  • 32,985
  • 16
  • 81
  • 107
  • That's a nice solution – Gearoid Murphy Aug 05 '13 at 17:49
  • Worth noting that this is c++11, so using semaphores might have to be the solution if you don't have that available – Yann Sep 24 '14 at 11:11
  • In old pthreads money, it would be done with `pthread_create()` followed by a `pthread_tryjoin_np()`, which would return EBUSY if the thread had not yet terminated. So, if std::thread does not support it, the underlying implementation probably does? – bazza Jul 10 '23 at 18:21
2

for what definition of "actively running code"? not that I know of, I'm not sure what state the thread is left in after it becomes joinable, in most cases I can think of you'd actually want fine grain control, like a flag set by the code running in that thread, anyway

for a platform specific solution, you could use GetThreadTimes

0

I just had a breakthrough with this. I've been looking for a simple and general solution. Here it is.

Using the Boost C++ Libraries, create a signal that returns a boolean. Prior to its first use, connect the signal to a slot that returns false. Create a boost::signals2::scoped_connection within your thread that returns true. This exploits the default behavior of boost::signals2::signal return types that returns the value of the last slot called. By using the scoped_connection at the beginning of your thread, this slot only remains connected while thread is running. Also, Boost signals2::signals contain internal mutexes that maintain thread safety.

#include <thread>
#include <boost/signals2.hpp>

int main(int argc, char* argv[])
{
   //This can be in a class or someplace else
   boost::signals2::signal<bool ()> ThreadRunning;

   // Be sure to capture 'this' if used in a class
   ThreadRunning.connect([]() {return false;});
   
   auto t = std::thread([]()
   {
      // 'c' is an arbitrary variable name.
      boost::signals2::scoped_connection c(ThreadRunning.connect[]() {return true;}));
      // Do your stuff.
   });

   if (TreadRunning())
      //Do stuff if the thread is still running

   t.join();

   return 0;
}

If the thread hasn't joined, but you want to see if it's completed running, you can insert an additional scope to your thread.

auto t = std::thread([]()
{
   {
      boost::signals2::scoped_connection c(ThreadRunning.connect[]() {return true;}));
      // Do your stuff.
   }
});

With this method, calling ThreadRunning() will return false even through the thread isn't joined.

While this method is threadsafe, there is the possibility that the thread will complete between when you call your signal and completing whatever you use this logic for.

  • A tiny small hole is that the scoped connection to the signal in the thread will get cleaned up as the thread is terminating, but the thread will still have more work to do in cleaning up whatever else needs cleaning up. If any other resource deleters block, then the main thread's join will get blocked too. A lot will depend on the clean up order, which I can never remember! Regardless, depending on implementation there may still be thread control objects to clean up after the thread function has cleaned up, and during that clean up the thread may still get preempted. – bazza Jul 10 '23 at 18:20
  • True. There's no perfect solution that will tell you a thread is completely dead. However, this can be useful to determine if the thread is effectively dead and that you can't do anything with it besides let it clean up. – Matthew Osborne Jul 12 '23 at 10:26