Home > database >  Cleanly exit Boost thread member of class
Cleanly exit Boost thread member of class

Time:04-26

I have a class that has a boost::thread member variable. I have a private member function that is run in that thread (see code below).

class Human
{
  public:
    Human()
        : m_thinkThread(&Human::think, this)
    { }

    ~Human()
    {
        m_thinkThread.interrupt();
        m_thinkThread.join();
    }

  private:
    void think()
    {
        // do some thinking...
    }

    boost::thread m_thinkThread;
};
  1. Do I need the interrupt and join calls and therefore the custom destructor? Or will the default destructor take care of exiting cleanly? If the default destructor is all I need, then what does it do "under the hood" to ensure the thread is exited cleanly?
  2. If I do however, need the interrupt and join calls, then my current setup has a bug because join() can throw, which will be an uncaught exception in a destructor. How would I handle this case?

Thank you

CodePudding user response:

Do I need the interrupt and join calls and therefore the custom destructor? Or will the default destructor take care of exiting cleanly? If the default destructor is all I need, then what does it do "under the hood" to ensure the thread is exited cleanly?

Yes. There's std::jthread in more recent standard versions, which would auto-join.

If I do however, need the interrupt and join calls, then my current setup has a bug because join() can throw, which will be an uncaught exception in a destructor. How would I handle this case?

If I remember correctly there's a join_nothrow operation as well. In case that's me remembering an implementation detail, consider using a thread guard.

This seems to have been added to Boost Thread after Anthony Williams' "Concurrency In Action" (chapter 2.1.3) which seems to have never received documentation.

struct Human
{
    Human() : m_thinkThread(&Human::think, this) {}

  private:
    void think() const;

    boost::thread m_thinkThread;
    boost::thread_guard<boost::interrupt_and_join_if_joinable> m_guard{m_thinkThread};
};

Live On Coliru

void Human::think() const {
    while (true) {
        boost::this_thread::sleep_for(boost::chrono::milliseconds(1500));
        std::cout << "Thinking..." << std::endl;
    }
}

int main() {
    Human plight;
    boost::this_thread::sleep_for(boost::chrono::seconds(10));
}

Prints

Thinking...
Thinking...
Thinking...
Thinking...
Thinking...
Thinking...

then cleanly shuts down after 10 seconds.

Caveats

There have been versions of boost where using thread-guards in a situation with nested interruptable threads there would be unhandled exceptions: see https://github.com/boostorg/thread/issues/366

  • Related