3

std::thread::join does not return, even if the thread routine is exited.

Guess, I have a class.

class A
{
public:
    A()
    {
        this->thr = std::thread(&A::foo, this);
    }
    ~A()
    {
        this->join();
    }
    void join()
    {
        this->cond.notify_all();
        if (this->thr.joinable())
        {
            this->thr.join();
        }
    }

private:
    void foo()
    {
        std::mutex mtx;
        std::unique_lock<std::mutex> lck(mtx);
        this->cond.wait(lck);
        MessageBox(L"I'm done!");
    }

private:
    std::thread thr;
    std::condition_variable cond;
};

My application contains the only instance of A. It is a global variable. If A::join is called from the destructor, std::thread::join blocks forever. If I call A::join manually (e.g. before exiting main), everything is alright.

My main looks like this:

A a;
int main()
{
    auto timeout = std::chrono::seconds(3);
    std::this_thread::sleep_for(timeout);

    // a.join();
}

By the way, MessageBox is always executed.

Is that the same problem as here?

Community
  • 1
  • 1
John Smith
  • 89
  • 11
  • Did [that answer](http://stackoverflow.com/a/17239943/2069064) not answer your question? – Barry Mar 03 '16 at 13:59
  • @Barry, It doesn't seem to be a great solution. I works, but what if the `main` is not so trivial? There're a lot of different ways of exiting from my application. Thus, I've got to `join` my threads manually every time I need it? – John Smith Mar 03 '16 at 14:10
  • @MAKAKOKO Sorry I was confused on what was going on. I retracted the comment. – NathanOliver Mar 03 '16 at 14:17
  • Btw put `notify_all()` under mutex, you have race condition there – Slava Mar 03 '16 at 14:49
  • The example works fine on vs2015 (with and without `a.join()`, `MessageBox` call was corrected) and there is no race condition with `notify_all()`. – knivil Mar 03 '16 at 14:51
  • @knivil Could be this: http://stackoverflow.com/questions/10915233/stdthreadjoin-hangs-if-called-after-main-exits-when-using-vs2012-rc - and maybe that is why it works on 2015 – Rudolfs Bundulis Mar 03 '16 at 15:17

2 Answers2

4

Yes it is the same bug as in the referenced link since your example also hangs on _Thrd_join. You could be interrested in this question which contains a far more detailed analysis.

Community
  • 1
  • 1
Rudolfs Bundulis
  • 11,636
  • 6
  • 33
  • 71
1

from your comment

"It doesn't seem to be a great solution. I works, but what if the main is not so trivial? There're a lot of different ways of exiting from my application. Thus, I've got to join my threads manually every time I need it?"

how about making A a std::unique_ptr within your main. that way, no matter how your main exits, it'll always destroy A before exiting main() and you won't have this problem.