views:

337

answers:

1

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.

+3  A: 

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.

laura
Note that you can accept your own answer to mark your question as answered.
MP24
Only after two days unfortunately. Thanks again for the help
laura