V Shreyas
V Shreyas

Reputation: 449

Thread joining using a destructor

This is a continuation to my question: Thread creation inside constructor

Now that I have successfully created a thread in a constructor, I know that it must be joined. As I am developing an API, I have no control over the main function so I can't join it there.

Will it be right to join the thread in the class destructor, considering that the instanced object of that class would have an application's lifetime?

Upvotes: 6

Views: 10420

Answers (4)

Chris Desjardins
Chris Desjardins

Reputation: 2720

I have come up with a threading pattern that I have found handles all of the weird situations in C++ regarding running threads in classes.

http://chrisd.nl/blog/how-to-run-threads/

Upvotes: 1

hyde
hyde

Reputation: 62777

You have encountered the one of the shortcomings of C++ RAII: Destructors can't easily report errors, and a destructors can't fail gracefully, because they have no return value and throwing exceptions is bad idea.

So if the other thread is not responding to a request to stop, what can destructor do? It can wait more or violently destroy the other thread or leave it running, none of which are very nice options. And then it can either ignore the situation, just log it, or throw an exception despite the risk of application terminating immediately, again not a very nice set of options.

So, you have at least 3 options

  • The joined thread is known to be well-behaved, so you know it will terminate promptly when requested, and join in destructor is safe. The risk is, program will hang on the join if thread isn't terminating.
  • You determine that the error handling options (explained above) available in destructor are sufficient, and join in destructor is ok. You have to add the error detection and handling code to destructor (for example a timeout).
  • Provide a separate "close" method, which perhaps takes timeout argument, and then returns error value or throws exception on failure.

With threads, a thread failing to terminate promptly can often be considered a programming error comparable to a segfault, so you could choose to terminate the application with helpful (to the developer) diagnostic message (2nd bullet point above), or just let the program hang (1st bullet point above). But this is a bit risky, because if down the road you need to create a thread which can't terminate quickly (it is doing a blocking system call, or it must notify the other end of a network connection, which may be slow), and it's a good idea to think how to solve this before locking down a design.

Upvotes: 2

Ami Tavory
Ami Tavory

Reputation: 76297

You could do that. However, are you really interested in the mechanism of launching a new thread, or are you perhaps interested in the effect of performing something asynchronously? If it's the latter, you can move to the higher level async mechanism:

#include <iostream>
#include <future>


void bar()
{
    std::cout << "I'm bar" << std::endl;
}

class foo
{
public:
    foo() :
        m_f(std::async(
            std::launch::async,
            bar))
    {

    }

    ~foo()
    {
        m_f.get();
    }

private:
    std::future<void> m_f;
};

int main ()
{
    foo f;
}
  • You're asking in the constructor to launch bar asynchronously. You don't care about managing the thread yourself - let the library handle that.

  • Place the resulting future in a member.

  • In the dtor, get the future.

Upvotes: 8

Johan Engblom
Johan Engblom

Reputation: 215

Sure, you could do. just make sure the thread will exist otherwise your program will hang forever on that join.

Upvotes: 1

Related Questions