So I have done some research, and have found you can create a boost::thread object and have it start with a non-static class function by using \"this\" and boost::bind etc.
The this
keyword is used with boost::bind
when the function object you're creating is bound to a object member function. Member functions can't exist apart from instances, so when creating a functor object out of a member function with boost::bind
, you need a pointer to an instance. That's exactly what the this
keyword actually is. If you use the this
keyword within a member function of a class, what you get is a pointer to the current instance of that class.
If you were to call bind
from outside a class member function, you might say something like:
int main()
{
Foo f;
boost::thread* thr = new boost::thread(boost::bind(&Foo::some_function, &f));
}
Here, we're using Foo::some_function as our thread function. But we can't use this
because we're calling bind
from main
. But the same thing could be achieved using this
if we called bind
from within a member function of Foo, like so:
void Foo::func1()
{
boost::thread* thr = new boost::thread(boost::bind(&Foo::some_function, this));
}
If a member function is static, or is simply a regular (non-member) function, then you don't need an instance pointer at all. You would just do:
boost::thread* thr = new boost::thread(some_regular_function);
In cases like this it is useful to think of non-static member functions as free functions that take the this
as first parameter, for example in your case void MainThreadFunc(Main* this)
.
boost::thread
accepts a nullary functor, so you have to pass it a nullary functor which contains a reference to the instance GUIMain
and calls GUIMain->MainThreadFunc
which, seen as I explained above, would be something like MainThreadFunc(GUIMain)
.
Boost (and now also C++ with TR1) provides helpers to create such functors, namely boost::bind
(or alternatively boost::lambda::bind
). The expression boost::bind(f, arg1, arg2, ...)
means "return a nullary functor which calls f(arg1, arg2, ...)
".
That said, you can use the following expression to create the thread:
GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain))
boost::bind is your friend (it can sometimes have a rough way of showing it though)!
use GUIThread = new boost::thread(boost::bind(&Main::MainThreadFunc, GUIMain));
and then make your MainThreadFunc a regular member. That means that you can use the instance variables directly like you would normally do.
Something like this:
class GUIMain {
public:
GUIMain() : m_Member(42) {}
void MainThreadFunc() {
// use all members as you would normally do
std::cout << m_Member << std::endl;
}
private:
int m_Member;
};
If your object is a functor, i.e. has an operator()
, you can pass an instance of it to boost::thread
. The operator()
does not need to be static. For example:
#include <boost/thread.hpp>
struct th {
void operator()();
};
void th::operator()()
{
for (;;) {
// stuff
}
}
int main()
{
th t;
boost::thread my_thread( t ); // takes a copy of t !
my_thread.join(); // blocks
return 0;
}
As others mentioned, when you want to call an object method in a new thread, you have to supply the address of that object. But you don't need to call boost::bind
, you can use the overloaded boost::thread
constructor like this:
GUIThread = new boost::thread(&Main::MainThreadFunc, GUIMain);
If the method is in the same class you use this
to get the address of the current instance, e.g.:
t = new boost::thread(&myclass::compute, this);
If the method has parameters, you can specify them after the second argument, e.g.:
t = new boost::thread(&myclass::compute, this, p1, p2);