Объекты ядра операционной системы и доступ к ним из потоков

Тема в разделе "WASM.WIN32", создана пользователем s3dworld, 30 авг 2011.

  1. s3dworld

    s3dworld Сергей

    Публикаций:
    0
    Регистрация:
    16 мар 2010
    Сообщения:
    387
    Адрес:
    Ртищево
    Всем доброго вечера!

    Пишу сетевой движок для работы под управлением операционной системы семейства Windows. Модель ввода/вывода я выбрал WSAAsyncSelect(), то есть мне понадобится окно и функция обработчик сообщений от операционной системы. А так как некоторые программы могут быть консольными, я решил чтобы библиотека сама создавала окно и обрабатывала сообщения. Раз она это будет делать сама, то для этого ей нужен отдельный поток.

    Создал поток. Поток регистрирует класс, создаёт окно и инициализирует работу с Windows сокетами через WSAStartup(). В этот момент основной поток программы ждёт созданный поток. Ждёт он два события: либо если поток завершится, либо если поток освободит указанное мною событие. Если поток завершится, я могу получить код его завершения, то есть узнать причину. Если же освободиться заранее определённое мною событие, то это значит что поток всё инициализировал и вошёл в цикл отлова сообщений от операционной системы.

    Вроде всё нормально. Но как выяснилось дальше, я совсем забыл про особенность потоков.

    Первое что я заметил, когда пытался создать сокет в основном потоке, через socket(), так это то, что мне приходила ошибка WSANOTINITIALISED (Или приложение не вызвало WSAStartup(), или произошла ошибка в WSAStartup()). Странно, я же её вызывал и она завершилась успешно в потоке. Тогда я переместил функцию инициализации работы с Windows сокетами в основной поток.

    Думал всё будет отлично. У меня объявлено так:

    Код (Text):
    1. HINSTANCE appInstance;
    2. HWND window;
    Конструктор же обнуляет значения:

    Код (Text):
    1. appInstance=0;
    2. window=0;
    И вот у меня созданный поток успешно завершает:

    Код (Text):
    1. window=CreateWindowEx(...);
    Успешно, то есть window не равна нулю. А потом из основного потока, когда я обращаюсь к window, оно содержит ноль. Я конечно до сих пор не понимаю почему там ноль. Ведь значение то общее. Одно дело что тут я вспомнил что у каждого потока своя таблица объектов ядра. Поэтому я и не могу в основном потоке использовать окно, созданное в дочернем потоке. Но почему ноль-то?!

    В общем не могу сейчас придумать, как бы мне всё это заставить правильно работать. Добиться нужно следующего:

    - Всего в программе должно быть два потока: основной поток программы и один дочерний поток.

    - Дочерний поток должен обрабатывать сообщения от операционной системы, чтобы определять события для сокетов (FD_ACCEPT, FD_CLOSE, FD_READ и FD_WRITE).

    - Основной поток программы устанавливает функции обратного вызова, которые вызывает дочерний поток при приходе какого-то события для сокета.

    - Как только функция обратного вызова сработала, пользователь оповещается что можно что-то сделать с сокетом (например считать данные) и уже может вызвать нужную функцию.

    Не состыковка проявилась вот в каком месте:

    Код (Text):
    1. #include "DNetTCP\DNetTCP.h"
    2.  
    3. void NetEvent(DNetTCP::IClient* _client,DNetTCP::EventType _eventType);
    4.  
    5. int main(void)
    6. {
    7.   DNetTCP::Result result;
    8.   DNetTCP::ICore* core=0;
    9.   DNetTCP::IClient* client=0;
    10.   DNetTCP::ParametersFunctionsClient pfc;
    11.  
    12.   memset(&pfc,0,sizeof(DNetTCP::ParametersFunctionsClient));
    13.  
    14.   result=DNetTCP::CreateCore(&core);
    15.  
    16.   if(result!=DNetTCP::Ok)
    17.   {
    18.     MessageBox(0,TEXT("Вот так вот!"),TEXT("Ошибка"),MB_ICONERROR);
    19.     return -1;
    20.   }
    21.  
    22.   result=core->Start(); // Инициализируется работа с сокетами в основном потоке и создаётся дочерний поток
    23.  
    24.   if(result!=DNetTCP::Ok)
    25.   {
    26.     core->Release();
    27.     MessageBox(0,TEXT("Вот так вот!"),TEXT("Ошибка"),MB_ICONERROR);
    28.     return -1;
    29.   }
    30.  
    31.   pfc.functionsGlobal.disconnect=&NetEvent;
    32.   pfc.functionsGlobal.disconnectError=&NetEvent;
    33.   pfc.functionsGlobal.message=&NetEvent;
    34.   pfc.functionsGlobal.error=&NetEvent;
    35.  
    36.   result=core->CreateClient(&client);
    37.  
    38.   if(result!=DNetTCP::Ok)
    39.   {
    40.     core->Release();
    41.     MessageBox(0,TEXT("Вот так вот!"),TEXT("Ошибка"),MB_ICONERROR);
    42.     return -1;
    43.   }
    44.  
    45.   result=client->Start(); // А тут уже я не вижу окно
    46.  
    47.   if(result!=DNetTCP::Ok)
    48.   {
    49.     core->Release();
    50.     MessageBox(0,TEXT("Вот так вот!"),TEXT("Ошибка"),MB_ICONERROR);
    51.     return -1;
    52.   }
    53.  
    54.   result=client->Connect("46.33.224.184",27015,&pfc);
    55.  
    56.   if(result==DNetTCP::Ok)
    57.     MessageBox(0,TEXT("Подключились!"),TEXT("Успех"),MB_ICONERROR);
    58.   else
    59.     MessageBox(0,TEXT("Не подключились!"),TEXT("Ошибка"),MB_ICONERROR);
    60.  
    61.   Sleep(5000);
    62.  
    63.   client->Release();
    64.   core->Release();
    65.  
    66.   return 0;
    67. }
    68.  
    69. void NetEvent(DNetTCP::IClient* _client,DNetTCP::EventType _eventType)
    70. {
    71.  
    72. }
    В момент когда я делаю:

    Код (Text):
    1. result=client->Start();
    Там внутри у меня проверяется значение window (нужно чтобы связать сокет с событием и указать в какое окно слать). Получается что я из первичного потока хочу указать окно, а окно то у меня создано и обрабатывается в дочернем потоке.

    Подскажи-те, как выкрутиться? Модель ввода/вывода не предлагать сменить.