CSocket :: OnReceive同时调用

时间:2014-02-19 01:09:08

标签: c++ multithreading mfc mutex vc6

我有一个奇怪的问题。

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. 第一次通话
  7. 我的问题:

    1. 如何才能对OnReceive进行两次并发调用
    2. 为什么Mutex不起作用(由于相同的threadid?)
    3. 我怎么能有两个具有相同ThreadID的执行路径???
    4. 当然,我怎么能解决这个问题?
    5. 请注意,仅当我发送大量小消息(<50Bytes)直到发送块时才会发生这种情况。总计约为500KB / s。如果我在每次发送之后放入睡眠(1)它就不会发生..但是当然会杀死我的传输速度。

1 个答案:

答案 0 :(得分:1)

好的,我找到了根本原因。在Log语句中使用Win32 Mutex,并使用以下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);
    }
}

等待清除Mutex或发布消息。 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());
}