Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does thread.join fail when called in destructor of global variable

I reduced my problematic code to the following. I have a class C that runs a member function on its own thread. In the destructor of C I want to cleanly exit this thread. This works fine as long as c is defined within main (1), but not when it is a global variable (2). In the latter case, I see that the thread function returns but that the t.join() hangs.

#include <mutex>
#include <condition_variable>
#include <thread>
#include <iostream>

using namespace std;

class C
{
public:
    C()
    {
        stop = false;
        t = thread(&C::ThreadFunc, this);
    }
    ~C()
    {
        stop = true;
        cv.notify_all();
        if (t.joinable())
        {
            cout << "joining" << endl;
            t.join();
            cout << "joined" << endl;
        }
    }

private:
    void ThreadFunc()
    {
        while (true)
        {
            unique_lock<mutex> lock(m);
            cv.wait(lock, [&]{return stop;});
            cout << "returning" << endl;
            return;
        }
    }

    thread t;
    mutex m;
    condition_variable cv;
    bool stop;
};

C c;  // does *not* work (2)

int _tmain(int argc, _TCHAR* argv[])
{
    C c;  // does work (1)
    return 0;
}

The reason I use a global variable is that it is actually part of a dll. When the destructor is triggered from DllMain on DLL_PROCESS_DETACH, the same problem occurs. Is there an explanation and a solution to this problem?

like image 970
Emile Avatar asked Oct 02 '22 19:10

Emile


1 Answers

It's a deadlock. You are holding a lock that t requires in order to terminate while you are waiting for t to terminate.

Say as part of t's detach process, it makes some calls into the DLL. How can the DLL sensibly handle a request when there is a thread (the thread that called join) that is partially attached to it? Once you start detaching, and until you finish detaching, the DLL is an inconsistent state and cannot sensibly handle thread attach and detach operations.

You really don't want to try to join a thread while your process is in a context you can't control.

like image 58
David Schwartz Avatar answered Oct 07 '22 20:10

David Schwartz