2016-06-22 3 views
1

В моем приложении MFC у меня есть рабочий поток, который прослушивает сетевое подключение, и как только появится какая-то информация, я звоню SendMessageToDescendants, чтобы отправить эту информацию через параметр lparam. Поэтому каждое окно кадра получает сообщение и, возможно, обрабатывает его через обработчик сообщений для сообщения WM_SYNCHRONOTIFICATION (WM_SYNCHRONOTIFICATION - это сообщение WM_APP+x).Использование SendMessageToDescendants между потоками

Код рабочего потока: (упрощены для краткости)

while (TRUE) 
{ 
    CNotificationMessage notificationmessage; 
    Listen(&notificationmessage); // blocking until some information arrives 

    m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif)); 

    // have all OnSynchroNotification handlers been called here ? 
} 

Обработчик сообщений в основном потоке:

LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2) 
{ 
    CNotificationMessage *pNotification = (CNotificationMessage*)p2; 

    // process message (ommited for brevity) 
} 

код работает отлично, но я не конечно, если по возвращении с SendMessageToDescendants все вызвали OnSynchroNotification.

+4

[Никогда не используйте различные SendMessage из потока] (http://stackoverflow.com/a/29603742/17034). –

ответ

2

Простейшее решение для использования - счетчик. Перед вызовом SendMessage инициализируйте общий счетчик числа дочерних окон, которые хотели бы обработать сообщение. Затем каждый обработчик сообщения отвечает за декремент счетчика, когда он завершает свою работу, и ваш цикл событий может проверить, что счетчик равен 0, прежде чем генерировать больше событий. В псевдо C++:

unsigned int sharedCount; // global/static shared value 

while (TRUE) 
{ 
    CNotificationMessage notificationmessage; 
    Listen(&notificationmessage); // blocking until some information arrives 

    unsigned int current = InterlockedCompareExchange(&sharedCount, activeWindowCount, 0); 
    if (current == 0) 
    { 
     m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif)); 
    } 
    else 
    { 
     // Still processing the last message. 
    } 

    while (InterlockedCompareExchange(&sharedCount, 0, 0) != 0) 
    { 
     Sleep(100); 
    } 
} 

LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2) 
{ 
    // Processing 
    InterlockedDecrement(&sharedCount); 
} 

несколько более сложного решения, но тот, который я лично предпочитаю, так как вы не должны гореть CPU ожидание завершения, чтобы создать событие для каждого сообщения окна обработки, а затем используйте WaitForMultipleObjects (или версию Ex), чтобы остановить цикл события до завершения. Опять же, в псевдо C++:

while (TRUE) 
{ 
    CNotificationMessage notificationmessage; 
    Listen(&notificationmessage); // blocking until some information arrives 

    m_pMainWnd->SendMessageToDescendants(WM_SYNCHRONOTIFICATION, NULL, (LPARAM)(newnotif)); 

    DWORD waitResult = WaitForMultipleObjects(activeWindowCount, FrameEvents, TRUE, INFINITE); 
    if (waitResult == WAIT_OBJECT_0) 
    { 
     // Success 
    } 
    else if (waitResult == WAIT_FAILED) 
    { 
     // Failure: Use GetLastError() to figure out why the function call failed. 
    } 

    // Reset the events 
}  

LRESULT CMyFrame::OnSynchroNotification(WPARAM p1, LPARAM p2) 
{ 
    // Processing 
    SetEvent(thisFramesEvent); 
} 

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

(обязательно Отказ от ответственности: Проверка ошибок и инициализация переменной были удалены из обоих из них ради краткости и читаемости Смотрите документацию о том, как проверить на наличие ошибок.).

Смежные вопросы