2014-02-19 29 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. 兩個同時通話
  3. 爲什麼互斥鎖不起作用(由於相同的螺紋?)
  4. 而我該如何兩個具有相同ThreadID的執行路徑?
  5. 而當然,我該如何解決這個問題?

請注意,只有在發送塊之前發送大量小消息(< 50字節)時纔會發生這種情況。總共大約500KB/s。如果我在每次發送之後放置睡眠(1),它不會發生......但是這種情況會導致我的傳輸速度。

回答

1

好吧,我找到了根本原因。在日誌聲明一個Win32互斥鎖使用,下面等待:

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()); 
} 
相關問題