37

Given below:

void test() 
{
  std::chrono::seconds dura( 20 );
  std::this_thread::sleep_for( dura );
}

int main()
{
  std::thread th1(test);
  std::chrono::seconds dura( 5 );
  std::this_thread::sleep_for( dura );
  return 0;
}

main will exit after 5 seconds, what will happen to th1 that's still executing?

Does it continue executing until completion even if the th1 thread object you defined in main goes out of scope and gets destroyed?

Does th1 simply sits there after it's finished executing or somehow gets cleaned up when the program terminates?

What if the thread was created in a function, not main - does the thread stays around until the program terminates or when the function goes out of scope?

Is it safe to simply not call join for a thread if you want some type of timeout behavior on the thread?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
kiki
  • 381
  • 1
  • 3
  • 6
  • Why don't you try it? – Ivan Aksamentov - Drop Dec 10 '14 at 03:15
  • 30
    @Drop Because that's no reliable way of learning about *guarantees*. – dyp Dec 10 '14 at 03:19
  • @dyp neither asking on Stackoverflow is. By compiling and running this 5-line exmple, at least he could find a clue. There is only one source of guarantees -- a standard. – Ivan Aksamentov - Drop Dec 10 '14 at 03:25
  • 9
    @Drop *"neither asking on Stackoverflow is"* Well, a good SO answer in my opinion quotes a reliable source (as you did). Not even the Standard itself however is a completely reliable source, since it contains defects. Compiler providers will often deviate from a literal interpretation e.g. to incorporate proposed resolutions of defect reports. Because of the existence of Undefined Behaviour, I think it's not good practice to learn about guarantees by trying things out. – dyp Dec 10 '14 at 03:30
  • 1
    I think "why don't you try it?" is a perfectly valid response, the question would be improved if it showed the OP had bothered to run some experiments before asking. "I tried it and my program terminated, is that expected?" is a better question than "what would happen if I did this?" It's not like we're talking about eating some unidentified berries found growing wild, C++11 compilers are freely available and running experiments is easy and educational. – Jonathan Wakely Dec 10 '14 at 12:12
  • 1
    @JonathanWakely I think dyp was referring to the general case, I have seen many questions where people make that comment and it would lead to the wrong conclusion, so I have to agree it is not helpful advice. In this specific case it probably would have lead to a more interesting question but we are assuming the OP has a machine they are free to install things on or knows about online compilers. I have been shocked at how many well informed developers don't know about online compilers. – Shafik Yaghmour Dec 10 '14 at 13:26

3 Answers3

27

If you have not detached or joined a thread when the destructor is called it will call std::terminate, we can see this by going to the draft C++11 standard we see that section 30.3.1.3 thread destructor says:

If joinable(), calls std::terminate(). Otherwise, has no effects. [ Note: Either implicitly detaching or joining a joinable() thread in its destructor could result in difficult to debug correctness (for detach) or performance (for join) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. —end note ]

as for a rationale for this behavior we can find a good summary in (Not) using std::thread

Why does the destructor of a joinable thread have to call std::terminate? After all, the destructor could join with the child thread, or it could detach from the child thread, or it could cancel the thread. In short, you cannot join in the destructor as this would result in unexpected (not indicated explicitly in the code) program freeze in case f2 throws.

and an example follows and also says:

You cannot detach as it would risk the situation where main thread leaves the scope which the child thread was launched in, and the child thread keeps running and keeps references to the scope that is already gone.

The article references N2802: A plea to reconsider detach-on-destruction for thread objects which is argument against the previous proposal which was detach on destruction if joinable and it notes that one of the two alternatives would be to join which could lead to deadlocks the other alternative is what we have today which is std::terminate on destruction if joinable.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • "or it could cancel the thread..." What does it mean to "cancel" a std::thread? By the way it's worth noting that C++20 adds jthread that joins on destruction. – pooya13 May 03 '20 at 06:03
6

std::thread::~thread()

If *this has an associated thread (joinable() == true), std::terminate() is called

Source: http://en.cppreference.com/w/cpp/thread/thread/~thread

This means that program like this is not at all well-formed or safe.

Note, however, that boost::thread::~thread() calls detach() instead in this case. (as user dyp stated in comments, this behavior is deprecated in more recent versions)

You could always workaround this using RAII. Just wrap your thread inside another class, that will have desired behavior on destruction.

Ivan Aksamentov - Drop
  • 12,860
  • 3
  • 34
  • 61
1

In C++11, you must explicitly specify 'what happens' when the newly created thread goes out of scope (our it's dtor is called). Sometimes, when we are sure that the main thread, is continuing, and our threads are acting as 'pipeline', it is safe to 'detach()' them; and sometimes when we are waiting for our WORKER threads to complete their operations, we 'join()' them.

As this says, the programmer must ensure that the destructor is never executed while the thread is still joinable.

Specify your multi-threaded strategy. In this example, std::terminate() is called.

mkr
  • 11
  • 3