views:

160

answers:

2

Hello, consider this:

class MyClass
{
public:
    void DoSomething() { };
};

std::vector<MyClass> A;

int main(int argc, char* const argv[])
{
    MyClass a;
    A.push_back(a);
    boost::thread newThread(&MyClass::DoSomething, &A.back());
}

It compiles, but, expectedly, it does not work. Any help?

A: 

(For lack of other input, I assume you're working on some VS version, on some Windows version).

(1) I assume you're trying to pass &A.back as an implicit 'this' argument. This would not work for regular member functions, which are defined as __thiscall - meaning the function expects the 'this' argument in the ecx register and not on the stack. Try declaring DoSomething as stdcall, or static (with an explicit 'this' argument).

(2) Drop the address-of-function. Boost::thread constructor requires the first argument to be 'callable' as is:

boost::thread newThread(MyClass::DoSomething, &A.back());

might eventually work.

Ofek Shilon
+4  A: 

The first problem is that your main function is spawning a thread, then immediately exiting. The thread will barely get a chance to run before the process terminates. So at a minimum you need to wait for the thread to finish, which you can do by adding newThread.join() to the end of main, thus:

int main(int argc, char* const argv[])
{
    MyClass a;
    A.push_back(a);
    boost::thread newThread(&MyClass::DoSomething, &A.back());
    newThread.join();
    return 0;
}

The other issue is you've got the thread object in the same scope as main, as a local variable. While you can do this in simple situations, you need to be careful about the scope of the boost::thread object, which needs to give it a lifetime at least as long as you expect your thread to run.

In the case where an object needs to run a thread on a member function, you are probably better off encapsulating the thread object inside the object, and having a simple run() method that starts the worker thread. That way you can encapsulate all the state and thread management in the one place, along with any mutexes and condition variables that you may need. A simple example would be something like:

class Worker
{
public:

    Worker();

    void start(int N)
    {
        m_Thread = boost::thread(&Worker::processQueue, this, N);
    }

    void join()
    {
        m_Thread.join();
    }

    // Worker thread where all processing occurs
    void processQueue(int N);

private:

    boost::thread m_Thread;
};

You would probably also want to add things like a flag that returns the thread state (eg. running, completed, waiting, etc).

I noticed your example uses a vector of object instances (ie. storing by value). Just be careful that you don't inadvertently end up performing operations that cause a copy to be implicitly created, as this can cause all sorts of problems with threads. (That's why the boost::thread object is non-copyable.)

I've written an article on threading with Boost that explains the various ways you can create threads, including how to run threads on member functions (see type 5).

gavinb
That's a great article you have there. I wish there was something like this in the actual boost documentation, I spent a lot of time staring and that before I had it all figured out, but yours has everything :-)
teeks99
Thanks! I tried to write what I found was missing when I learned it. I've got two more articles in draft form, which I hope to put up soon.
gavinb