When we start a thread, there are two options. Either we will wait for the
thread to finish or we will not wait for it. A mechanism for waiting is
.join() member function. This is what we did in the first
.detach() member function is the other option: not waiting
for the thread to finish.
Therefore, we must choose between these two options. If we don’t detach or join
the thread, the program will crash! If you don’t believe me, comment a
.join() call in
compile and run the program. You should get an error message:
Thus, we must call either
detach. The second option is not problematic. The
.detach() is invoked right after the construction of a
The first approach, however, has some problems. Invoking the
.join() right after constructor doesn’t make sense, because
there is no need for the new thread in this case. Therefore, there is some code
between the construction of the thread and the
But this code can emit an exception, which consequently means that the
.join() will not be invoked and the program will crash.
The solution is a
Guard class. Let us have a look at it.
An object of the class has a reference to a thread. The destructor checks if the
thread is joinable and then joins it. A thread is joinable if
.detach() were not called
yet. A guard object can not be copied, because we declared copy constructor and
copy assignment operator with
=delete. Inability to copy
means that the object can not outlive the scope of referenced thread.
This class guarantees that
.join() member function will be
called in any case. When the function ends, the destructors of all objects in
the scope are called before the program exits. This also happens if the function
raises an exception and ends prematurely.
Thanks to Nino Bašić for comments and suggestions. Now the article looks more organized!
We learned why are the plain threads dangerous and how to make them safer with a
In the next article, we will look how to pass an argument to a thread.