Reputation: 295
I need to call a member function of a class through thread but I don't want to use Boost library binding concept and the class I have to use doesn't have any static function to help out. I tried to use STL mem_fun_ref
but I received a compile time error.
base b;
handle = CreateThread(NULL, 0, LPTHREAD_START_ROUTINE(bind2nd(mem_fun_ref(&base::show), &b)),
NULL, NULL, &dword);
class B{
public:
void show(){
cout << "show";
}
};
Upvotes: 0
Views: 453
Reputation: 645
This is C WinAPI function, here's the declaration:
HANDLE WINAPI CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
The problem is the LPTHREAD_START_ROUTINE type defines a pointer to callback function, and not C++ method that has "hidden" this parameter.
Here's good example how to bypass it: http://blogs.msdn.com/b/oldnewthing/archive/2004/01/09/49028.aspx
class SomeClass {
...
static DWORD CALLBACK s_ThreadProc(LPVOID lpParameter)
{
return ((SomeClass*)lpParameter)->ThreadProc();
}
DWORD ThreadProc()
{
... fun stuff ...
}
};
Upvotes: 1
Reputation: 153810
I don't know about CreateThread()
but looks like a C-style interface to thread creation: you probably won't be able to pass through a function object. Most likely, the start function type is the moral equivalent of
extern "C" typedef void (*entry_funciont)(void*);
possibly with a few extra parameters and returning something different than void
. You'll need a forwarding function to recover your function object for which you'll need to know the exact type of the function object passed to the CreateThread()
function as the "user data" (I'd guess where you pass NULL
right after you function object. You could use something along the lines of this:
struct entry_base {
virtual ~entry_base() {}
virtual void call() = 0;
};
template <typename Fun>
struct entry
: entry_base {
Fun fun;
entry(Fun fun): d_fun(fun) {}
void call() {
this->d_fun();
delete this;
}
};
template <typename Fun>
entry_base* make_entry(Fun fun) {
return new entry<Fun>(fun);
}
extern "C" void call_entry(void* entry) {
static_cast<entry_base*>(entry)->call();
}
... which can then be used something like this:
base* b = ...; // you can't use a local object here!
handle = CreateThread(NULL, 0,
LPTHREAD_START_ROUTINE(&call_entry),
make_entry(bind2nd(mem_fun_ref(&base::show), &b)),
NULL, &dword);
Note that I'm speculating somewhat about the interface to CreateThread()
, i.e., the user data pointer may very well go into a different location. However, binding to a pointer to a local object is almost certainly not going to work: this object is likely to go out of scope while the thread is running and it would remove the basis for the object running.
Upvotes: 1