views:

1140

answers:

2

I'm trying to write a fairly simple threaded application, but am new to boost's thread library. A simple test program I'm working on is:

#include <iostream>
#include <boost/thread.hpp>

int result = 0;
boost::mutex result_mutex;

boost::thread_group g;

void threaded_function(int i)
{
    for(; i < 100000; ++i) {}

    {
     boost::mutex::scoped_lock lock(result_mutex);
     result += i;
    }
}

int main(int argc, char* argv[])
{
    using namespace std;

    // launch three threads
    boost::thread t1(threaded_function, 10);
    boost::thread t2(threaded_function, 10);
    boost::thread t3(threaded_function, 10);

    g.add_thread(&t1);
    g.add_thread(&t2);
    g.add_thread(&t3);

    // wait for them
    g.join_all();

    cout << result << endl;

    return 0;
}

However, when I compile and run this program I get an output of

$ ./test 
300000
test: pthread_mutex_lock.c:87: __pthread_mutex_lock: Assertion `mutex->__data.__owner == 0' failed.
Aborted

Obviously, the result is correct but I'm worried about this error message, especially because the real program, which has essentially the same structure, is getting stuck at the join_all() point. Can someone explain to me what is happening? Is there a better way to do this, i.e. launch a number of threads, store them in a external container, and then wait for them all to complete before continuing the program?

Thanks for your help.

+1  A: 

add_thread() takes ownership of thread you pass in. Thread group deletes the thread. In this example you are deleting memory allocated on stack, pretty much a capital offence.

Member function add_thread()

void add_thread(thread* thrd);

Precondition:

The expression delete thrd is well-formed and will not result in undefined behaviour.

Effects:

Take ownership of the boost::thread object pointed to by thrd and add it to the group.

Postcondition:

this->size() is increased by one.

Not sure if that's what's wrong in your code, or if this is just example bug. Otherwise code looks fine.

Eugene
+3  A: 

I think you problem is caused by the thread_group destructor which is called when your program exits. Thread group wants to take responsibility of destructing your thread objects. See also in the boost::thread_group documentation.

You are creating your thread objects on the stack as local variables in the scope of your main function. Thus, they have already been destructed when the program exits and thread_group tries to delete them.

As a solution, create your thread objects on the heap with new and let the thread_group take care of their destruction:

boost::thread *t1 = new boost::thread(threaded_function, 10);
...
g.add_thread(t1);
...
VoidPointer
You should remove the ellipsis between the "new" memory allocation and handing it off to the thread_group. Otherwise if something goes wrong (i.e. throws) in the intervening code, you will leak the thread.
John Zwinck
Yes, this appears to be the case and was the cause of the bug in the larger program as well. The working example now uses:// launch three threadsg.add_thread(new boost::thread(threaded_function, 10));g.add_thread(new boost::thread(threaded_function, 10));g.add_thread(new boost::thread(threaded_function, 10));
scandido