Создать поток не принимает функцию-член - PullRequest
2 голосов
/ 23 мая 2010

Я пытаюсь создать класс для сетевого программирования. Это создаст сокет общего назначения с резьбой.

Но когда я попытался создать поток, используя createthread (). Третий аргумент - ошибки. И из сети я узнал, что не могу использовать функции-члены в качестве аргумента для createthread ().

Есть ли что-нибудь, с помощью чего я могу этого достичь?

Ответы [ 3 ]

16 голосов
/ 23 мая 2010

Самый простой способ справиться с этим - создать функцию-заглушку, которая вызывает ваш класс.

UINT tid
HANDLE hThread = CreateThread(NULL, 0, myThreadStub, this, 0, &tid);

....

unsigned long WINAPI myThreadStub(void *ptr) 
{
    if (!ptr) return -1;
    return ((MyClass*)ptr)->ThreadMain();
}

CreateThread () позволяет передавать аргумент функции потока (параметр 4 вызова CreateThread ()).Вы можете использовать это, чтобы передать указатель на ваш класс.Затем вы можете заставить потоковую заглушку привести этот указатель обратно к нужному типу и затем вызвать функцию-член.Вы даже можете иметь myThreadStub в качестве статического члена «MyClass», что позволяет ему получать доступ к закрытым членам и данным.

Если у вас установлен boost, вы можете использовать boost:: связать, чтобы сделать это без создания функции-заглушки.Я никогда не пробовал это на Windows, поэтому я не могу сказать наверняка, что это будет работать (потому что функция обратного вызова должна быть вызовом WINAPI), но если она работает, это будет выглядеть примерно так:

HANDLE hThread = CreateThread(NULL, 0, boost::bind(&MyClass::ThreadFunction, this), NULL, 0, &tid);

Где функция потока - это нестатическая функция-член, которая принимает один аргумент void *.

3 голосов
/ 14 ноября 2011

Существует простой способ решения проблемы.

Взгляните на Функция обратного вызова ThreadProc :


    DWORD WINAPI ThreadProc(
      <b>__in  LPVOID lpParameter</b>
    );

А теперь на Функция CreateThread :


    HANDLE WINAPI CreateThread(
      __in_opt   LPSECURITY_ATTRIBUTES lpThreadAttributes,
      __in       SIZE_T dwStackSize,
      __in       LPTHREAD_START_ROUTINE lpStartAddress,
      <b>__in_opt   LPVOID lpParameter</b>,
      __in       DWORD dwCreationFlags,
      __out_opt  LPDWORD lpThreadId
    );

Используйте статический метод в качестве потоковой процедуры, но вызовите его из метода-члена и передайте на него указатель объекта:


    #include <windows.h>

    class MyClass {
     public:
      void CreateThreadForObject() {
        LPSECURITY_ATTRIBUTES security_attributes = 0;
        SIZE_T stack_size = 0;
        LPTHREAD_START_ROUTINE start_routine = &MyClass::ThreadProcForObject;
        <b>LPVOID param = this;</b>
        DWORD creation_flags = 0;
        LPDWORD thread_id = 0;
        CreateThread(security_attributes, stack_size, start_routine, param,
                     creation_flags, thread_id);
      }

     private:
      static DWORD WINAPI ThreadProcForObject(<b>LPVOID param</b>) {
        <b>MyClass* instance = reinterpret_cast<MyClass*>(param);</b>
        if (!instance) return 1;
        // ...
        return 0;
      }
    };

Извините, я просто надеваюне хватает времени, чтобы написать хороший пример.Но я думаю, ты понимаешь путь.

0 голосов
/ 25 июля 2010

При потере я получил, сам факт, в CreateThread , если вы передаете сокет , то нет проблем.Потому что CreateThread является заботящимся об этом сокете .Но если вы передаете в качестве объекта, который имеет сокет , то CreateThread означает , не заботясь о сокете , и этозаканчивается неверным сокетом в новом потоке .

Успешный код ниже

SOCKET s=socket(....);
bind(s,...);
listen(s,...);
SOCKET temp=accept(s,(sockaddr *)&addrNew,&size);
DWORD threadId;
HANDLE thread=CreateThread(NULL,0,&MyThreadFunction,(LPVOID)(temp),0,&threadId);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...