2014-02-19 3 views
1

У меня странная проблема.CSocket :: OnReceive, вызываемый одновременно

void MySocket::OnReceive(int nErrorCode) 
{ 
    static CMutex mutex; 
    static int depth=0; 
    static int counter=0; 

    CSingleLock lock(&mutex, true); 
    Receive(pBuff, iBuffSize-1); 
    counter++; 
    depth++; //<-- Breakpoint 
    log("Onreceive: enter %d %d %d", GetCurrentThreadId(), counter, depth); 
    ..... 
    Code handling data 
    depth--; 
    log("Onreceive: exit %d %d %d", GetCurrentThreadId(), counter, depth); 
} 

Результаты в этом журнале заявление:

02/19/2014 08:33:14:982 [DEBUG] Onreceive Enter: 3200 1 2 
02/19/2014 08:34:13:726 [DEBUG] Onreceive Exit : 3200 2 1 
02/19/2014 08:32:34:193 [DEBUG] Onreceive Enter: 3200 0 1 <- Log statement was created but interrupted before it was written to disk 
02/19/2014 08:34:13:736 [DEBUG] Onreceive Exit : 3200 2 0 

Теперь, что происходит:

  1. Я запустить программу и отладчик останавливается в точке останова
  2. пошагово в журнал
  3. Некоторые, где в журнале отладчик возвращается к точке останова
  4. Это вторая запись в OnReceive
  5. Второй вызов завершает
  6. Первый вызов продолжается

Мои вопросы:

  1. Как это возможно, чтобы получить два одновременных вызовов в OnReceive
  2. Почему Mutex не работает (из-за того же самого потока?)
  3. И как я могу два пути выполнения с одним и тем же ThreadID ???
  4. И, конечно, как я могу это исправить ??

Обратите внимание, что это происходит только в том случае, если я отправляю много мелких сообщений (< 50Bytes) до блоков отправки. В общей сложности это около 500 КБ/с. Если я поставлю Сон (1) после каждого отправления, этого не произойдет ... но это, конечно, убивает мою скорость передачи.

ответ

1

Хорошо, я нашел причину. В заявлении журнала Win32-мьютекс используется и следующие Wait:

DWORD dwResult = MsgWaitForMultipleObjects(nNoOfHandle, handle, FALSE, dwTimeout, QS_POSTMESSAGE|QS_ALLPOSTMESSAGE|QS_SENDMESSAGE|QS_TIMER); 
if (dwResult == WAIT_OBJECT_0 + nNoOfHandle) // new message is in the queue, let's clear 
{ 
    MSG Msg; 
    while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) 
    { 
     ::TranslateMessage(&Msg); 
     ::DispatchMessage(&Msg); 
    } 
} 

Это ждет, когда мьютекс должен быть очищен или для сообщения будут опубликованы. CSocket отправляет сообщения в поток при получении данных и вызывает вызов OnReceive. Таким образом, этот код вызвал проблему, когда в ожидании мьютекса он обрабатывал входящие сообщения и снова вызывал OnReceive.

Одним из путей решения это должно было предотвратить CSocket разместить больше уведомлений, как это:

void MySocket::OnReceive(int nErrorCode) 
{ 
    /* Remove FD_READ notifications */ 
    VERIFY(AsyncSelect(FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE)); 

    OldOnReceive(nErrorCode); 

    /* Restore default notifications */ 
    VERIFY(AsyncSelect()); 
} 
Смежные вопросы