Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must one call join() or detach() before thread destruction?

I don't understand why when an std::thread is destructed it must be in join() or detach() state.

Join waits for the thread to finish, and detach doesn't. It seems that there is some middle state which I'm not understanding. Because my understanding is that join and detach are complementary: if I don't call join() than detach() is the default.

Put it this way, let's say you're writing a program that creates a thread and only later in the life of this thread you call join(), so up until you call join the thread was basically running as if it was detached, no?

Logically detach() should be the default behavior for threads because that is the definition of what threads are, they are parallelly executed irrespective of other threads.

So when the thread object gets destructed why is terminate() called? Why can't the standard simply treat the thread as being detached?

I'm not understanding the rationale behind terminating a program when either join() or detached() wasn't called before the thread was destructed. What is the purpose of this?

UPDATE:

I recently came across this. Anthony Williams states in his book, Concurrency In Action, "One of the proposals for C++17 was for a joining_thread class that would be similar to std::thread, except that it would automatically join in the destructor much like scoped_thread does. This didn’t get consensus in the committee, so it wasn’t accepted into the standard (though it’s still on track for C++20 as std::jthread)..."

like image 869
Moshe Rabaev Avatar asked Jul 16 '19 23:07

Moshe Rabaev


People also ask

What is the purpose of detaching threads?

thread::detachSeparates the thread of execution from the thread object, allowing execution to continue independently. Any allocated resources will be freed once the thread exits.

What do you mean by join () and joinable () in multithreading?

If the program needs to know when that thread of execution has completed, some other mechanism needs to be used. join() cannot be called on that thread object any more, since it is no longer associated with a thread of execution. It is considered an error to destroy a C++ thread object while it is still "joinable".

What happens if a thread is not joined?

If you don't join these threads, you might end up using more resources than there are concurrent tasks, making it harder to measure the load. To be clear, if you don't call join , the thread will complete at some point anyway, it won't leak or anything. But this some point is non-deterministic.

Can you join a detached thread?

5.6 [ISO/IEC 9899:2011], states that a thread shall not be joined once it was previously joined or detached. Similarly, subclause 7.26. 5.3 states that a thread shall not be detached once it was previously joined or detached.


2 Answers

Technically the answer is "because the spec says so" but that is an obtuse answer. We can't read the designers' minds, but here are some issues that may have contributed:

With POSIX pthreads, child threads must be joined after they have exited, or else they continue to occupy system resources (like a process table entry in the kernel). This is done via pthread_join(). Windows has a somewhat analogous issue if the process holds a HANDLE to the child thread; although Windows doesn't require a full join, the process must still call CloseHandle() to release its refcount on the thread.

Since std::thread is a cross-platform abstraction, it's constrained by the POSIX requirement which requires the join.

In theory the std::thread destructor could have called pthread_join() instead of throwing an exception, but that (subjectively) that may increase the risk of deadlock. Whereas a properly written program would know when to insert the join at a safe time.

See also:

  • https://en.wikipedia.org/wiki/Zombie_process
  • https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa
  • https://docs.microsoft.com/en-us/windows/win32/procthread/terminating-a-process
like image 171
fifoforlifo Avatar answered Sep 26 '22 08:09

fifoforlifo


You're getting confused because you're conflating the std::thread object with the thread of execution it refers to. A std::thread object is a C++ object (a bunch of bytes in memory) that acts as a reference to a thread of execution. When you call std::thread::detach what happens is that the std::thread object is "detached" from the thread of execution -- it no longer refers to (any) thread of execution, and the thread of execution continues running independently. But the std::thread object still exists, until it is destroyed.

When a thread of execution completes, it stores its exit info into the std::thread object that refers to it, if there is one (If it was detached, then there isn't one, so the exit info is just thrown away.) It has no other effect on the std::thread object -- in particular the std::thread object is not destroyed and continues to exist until someone else destroys it.

like image 43
Chris Dodd Avatar answered Sep 23 '22 08:09

Chris Dodd