Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Joining a boost::thread instance in the destructor

I'm seeing an issue where a call to boost's thread->join in a destructor leads to a deadlock. I don't understand why, and I'm not too keen on keeping code that just works (and I don't understand why it does) in the project.

Class declaration (I've stripped the run() method of try/catch for brevity: according to the boost thread documentation, the result should be the same with or without it):

class B 
{
public:
    void operator()(){run();}
    void run();
    void shutdown();
    ~B();
    B();
    boost::thread *thr;
    bool shutdown_requested;
};

void B::shutdown()
{
    shutdown_requested = true;

    if (thr != NULL)
    {
        thr->interrupt();
        thr->join(); // deadlock occurs here!
        delete thr;
        thr = NULL;
    }
}

B::~B()
{
    shutdown();
}

B::B()
{
    thr = new boost::thread(boost::ref(*this));
}

void B::run()
{
    while (!shutdown_requested)
    {
        boost::xtime xt;
        boost::xtime_get(&xt, boost::TIME_UTC);
        xt.sec += 30;
        boost::this_thread::sleep(xt);
    }
}

Snippet which does not work:

int main()
{
    B *b = new B;

    Sleep(5000);
    printf("deleting \n");fflush(stdout);
//    b->shutdown();
    delete b;
    printf("done\n");fflush(stdout);

    return 0;
}

Snippet which works:

int main()
{
    B *b = new B;

    Sleep(5000);
    printf("deleting \n");fflush(stdout);
    b->shutdown();
    delete b;
    printf("done\n");fflush(stdout);

    return 0;
}

I think the reason for this behavior has something to do with this snippet of the boost documentation:

the user of Boost.Thread must ensure that the referred-to object outlives the newly-created thread of execution.

But I don't really understand why the deadlock - joining the thread would not call the destructor on B and the object itself is not deleted when the run() method is supposed to exit.

like image 200
laura Avatar asked Nov 02 '09 11:11

laura


1 Answers

I've found the issue: it boils down to an over-zealous programmer.

I had originally compiled my project using DUMA (http://sourceforge.net/projects/duma/) to see if my implementation of the current module was leak-free. Unfortunately, my test sandbox also had the duma settings on, which I did not realize until I stepped through the code in a debugger.

After removing all memory leak-detection, everything works as expected.

like image 72
laura Avatar answered Oct 21 '22 14:10

laura