Мне нужно вызвать функцию-член класса через поток, но я не хочу использовать концепцию привязки библиотеки Boost, и класс, который я должен использовать, не имеет никакой статической функции, чтобы помочь. Я попытался использовать STL mem_fun_ref
но получил ошибку времени компиляции.
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";
}
};
Я не знаю о CreateThread()
но выглядит как интерфейс стиля C для создания потоков: вы, вероятно, не сможете пройти через объект функции. Скорее всего, тип функции запуска - это моральный эквивалент
extern "C" typedef void (*entry_funciont)(void*);
возможно, с несколькими дополнительными параметрами и возвращением чего-то другого, чем void
. Вам понадобится функция пересылки для восстановления вашего функционального объекта, для которого вам нужно будет знать точный тип объекта функции, переданного функции CreateThread()
в качестве "пользовательских данных" (я бы предположил, что вы передаете NULL
вправо после того, как вы используете объект. Вы можете использовать что-то в этом направлении:
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();
}
... который затем можно использовать примерно так:
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);
Обратите внимание, что я немного размышляю об интерфейсе с CreateThread()
, то есть указатель пользовательских данных вполне может перейти в другое место. Однако привязка к указателю на локальный объект почти наверняка не сработает: этот объект, скорее всего, выйдет за пределы области, пока поток запущен, и он удалит базу для выполняемого объекта.
Это функция C WinAPI, здесь декларация:
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
);
Проблема заключается в том, что тип LPTHREAD_START_ROUTINE определяет указатель на функцию обратного вызова, а не метод C++, который имеет "скрытый" этот параметр.
Вот хороший пример того, как обойти его: 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 ...
}
};