«оконная процедура» вновь созданного потока без окна - PullRequest
2 голосов
/ 13 ноября 2009

Я хочу создать поток для некоторых записей БД, которые не должны блокировать пользовательский интерфейс в случае, если БД там нет. Для синхронизации с основным потоком я бы хотел использовать сообщения Windows. Основной поток отправляет данные для записи в поток записи.

Отправка не является проблемой, так как CreateThread возвращает дескриптор вновь созданного потока. Я думал о создании стандартного цикла событий Windows для обработки сообщений. Но как мне получить оконную процедуру в качестве цели для DispatchMessage без окна?

Стандартный цикл событий Windows (из MSDN):

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{ 
    if (bRet == -1)
    {
        // handle the error and possibly exit
    }
    else
    {
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
    }
} 

Почему сообщения Windows? Потому что они быстрые (окна полагаются на них) и поточно-ориентированные. Этот случай также особенный, так как нет необходимости во втором потоке читать какие-либо данные. Он просто должен получить данные, записать их в БД, а затем дождаться поступления следующих данных. Но это именно то, что делает стандартный цикл обработки событий. GetMessage ждет данных, затем данные обрабатываются, и все начинается снова. Существует даже определенный сигнал для завершения потока, который хорошо понятен - WM_QUIT.

Другие конструкции синхронизации время от времени блокируют один из потоков (критическая секция, семафор, мьютекс). Что касается событий, упомянутых в комментарии, я их не знаю.

Ответы [ 3 ]

1 голос
/ 13 ноября 2009

Это может показаться противоречащим здравому смыслу, но для сообщений, у которых нет окон, на самом деле лучше создать скрытое окно с помощью вашего окна, чем вручную фильтровать результаты GetMessage() в насосе сообщений.

Тот факт, что у вас есть HWND, означает, что до тех пор, пока в правом потоке будет запущен насос сообщений, сообщение будет где-то маршрутизироваться. Учтите, что многие функции, даже внутренние Win32, имеют свои собственные обработчики сообщений (например MessageBox()). И код для MessageBox() не будет знать, чтобы вызывать ваш пользовательский код после его GetMessage(), если только нет дескриптора окна и процедуры окна, о которых DispatchMessage() будет знать.

Создавая скрытое окно, вы попадаете под любой насос сообщений, работающий в вашей ветке, даже если он не написан вами.

РЕДАКТИРОВАТЬ: но не просто поверьте мне на слово, посмотрите эти статьи от Рэймонда Чена из Microsoft.

1 голос
/ 13 ноября 2009

ПРИМЕЧАНИЕ : используйте этот код только в том случае, если вам не нужен какой-либо интерфейс, связанный с пользовательским интерфейсом, или какой-либо код, связанный с COM. За исключением таких угловых случаев, этот код работает правильно: особенно хорошо для чистого рабочего потока, ограниченного вычислениями.

DispathMessage и TranslateMessage не нужны, если у потока нет окна. Так что просто игнорируйте это. HWND не имеет никакого отношения к вашему сценарию. Вам вообще не нужно создавать какие-либо окна. Обратите внимание, что для обработки сообщений, связанных с интерфейсом Windows, таких как WM_KEYDOWN и WM_PAINT, необходимы две * функции сообщений.

Я также предпочитаю сообщения Windows для синхронизации и связи между потоками, используя PostThreadMessage и GetMessage или PeekMessage. Я хотел вырезать и вставить из своего кода, но я просто кратко набросал идею.

#define WM_MY_THREAD_MESSAGE_X   (WM_USER + 100)
#define WM_MY_THREAD_MESSAGE_Y   (WM_USER + 100)


// Worker Thread: No Window in this thread
unsigned int CALLBACK WorkerThread(void* data)
{
  // Get the master thread's ID
  DWORD master_tid = ...;
  while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
  { 
    if (bRet == -1)
    {
      // handle the error and possibly exit
    }
    else
    {
      if (msg.message == WM_MY_THREAD_MESSAGE_X)
      {
        // Do your task

        // If you want to response,
        PostThreadMessage(master_tid, WM_MY_THREAD_MESSAGE_X, ... ...);
      }

      //...
      if (msg.message == WM_QUIT)
        break;
    }
  }
  return 0;
}


// In the Master Thread
//
// Spawn the worker thread
CreateThread( ... WorkerThread ... &worker_tid);

// Send message to worker thread
PostThreadMessage(worker_tid, WM_MY_THREAD_MESSAGE_X, ... ...);

// If you want the worker thread to quit
PostQuitMessage(worker_tid);

// If you want to receive message from the worker thread, it's simple
// You just need to write a message handler for WM_MY_THREAD_MESSAGE_X
LRESULT OnMyThreadMessage(WPARAM, LPARAM)
{
  ...
}

Я немного боюсь, что это то, что вы хотели. Но код, я думаю, очень легко понять. В общем случае поток создается без очереди сообщений. Но когда вызывается связанная с окном функция сообщения, то очередь сообщений для потока инициализируется. Пожалуйста, обратите внимание, что для отправки / получения оконных сообщений окно не требуется.

0 голосов
/ 13 ноября 2009

Вам не нужна оконная процедура в вашем потоке, если у потока нет реальных окон для управления. Как только поток вызвал Peek / GetMessage (), у него уже есть то же сообщение, которое получит оконная процедура, и, таким образом, он может действовать немедленно Отправка сообщения необходима только тогда, когда задействованы реальные окна. Рекомендуется отправлять любые сообщения, которые вас не интересуют, в случае, если другие объекты, используемые вашим потоком, имеют свои собственные окна внутри (например, ActiveX / COM). Например:

while( (bRet = GetMessage(&msg, NULL, 0, 0)) != 0 )
{
    if (bRet == -1)
    {
      // handle the error and possibly exit
    }
    else
    {
        switch( msg.message )
        {
            case ...: // process a message
                ...
                break;
            case ...: // process a message
                ...
                break;
            default: // everything else
                TranslateMessage(&msg);
                DispatchMessage(&msg);
                break;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...