1

私のアプリケーションは、受信したシリアル データを非同期的に処理するために別のスレッドを使用しています。PC は予想どおり受信ハンドラーに入りますが、そこから奇妙なことが起こります。

これは私のスレッド関数です:

// Create event for OVERLAPPED structure.
s_ov.hEvent = ::CreateEvent(
    NULL,                           // No security
    TRUE,                           // Create a manual-reset event object
    FALSE,                          // Initial state is non-signaled
    NULL                            // No name specified
    );

// Load event handles.
pHandles[0] = s_hSerialPortRxThreadExitEvent;

while ( bContinue )
{
    if ( !::WaitCommEvent( s_hSerialPort, &dwEventMask, &s_ov ) )
    {
        if ( ::GetLastError() != ERROR_IO_PENDING )
        {
            TRACE(_T("SerialPortRxThreadFn : Call to WaitCommEvent failed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
            return ::GetLastError();
        }
    }

    pHandles[1] = s_ov.hEvent;

    dwObjectWaitState = ::WaitForMultipleObjects( 2, pHandles, FALSE, INFINITE );

    switch ( dwObjectWaitState )
    {
    case WAIT_ABANDONED:
        TRACE(_T("SerialPortRxThreadFn : Owner thread terminated prematurely.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ERROR_ARENA_TRASHED, __WFILE__, __LINE__);
        return ERROR_ARENA_TRASHED;
        break;

    case WAIT_TIMEOUT:
        TRACE(_T("SerialPortRxThreadFn : The timeout is set to INFINITE; there should be no timeout.  State is nonsignaled.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), WAIT_TIMEOUT, __WFILE__, __LINE__);
        return WAIT_TIMEOUT;
        break;

    case WAIT_FAILED:
        TRACE(_T("SerialPortRxThreadFn : Call to WaitCommEvent failed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
        return ::GetLastError();
        break;

    case WAIT_OBJECT_0:             // thread exit event signalled
        bContinue = FALSE;

        if ( !::ResetEvent( pHandles[0] ) )
        {
            TRACE(_T("SerialPortRxThreadFn  : Failed to reset the serial port thread exit event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
            return ::GetLastError();
        }
        break;

    case WAIT_OBJECT_0 + 1:         // OVERLAPPED structure event signalled
        // Read data from serial port.
        if ( !::ReadFile( s_hSerialPort, pBuf, RX_BUF_SIZE, &dwWritten, &s_ov ) ) // <- Set breakpoint here
        {
            TRACE(_T("SerialPortRxThreadFn : Call to ReadFile filed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
            return ::GetLastError();
        }

        // Discontinue thread operation if there are no more bytes in the serial port receive buffer.
        if ( dwWritten == 0 ) // <- Or, set breakpoint here
        {
            bContinue = FALSE;
        }
        // Copy the received bytes to the thread-safe buffer.
        else if ( !s_pobjRxRingBuffer->Add( pBuf, dwWritten, TRUE ) )
        {
            TRACE(_T("SerialPortRxThreadFn : Failed to add bytes to ring buffer.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ERROR_INSUFFICIENT_BUFFER, __WFILE__, __LINE__);
            return ERROR_INSUFFICIENT_BUFFER;
        }
        else if ( s_SpCallbackFn != NULL )
        {
            // Notify application of received data.
            if ( (dwRetVal = s_SpCallbackFn( s_pobjRxRingBuffer->ItemsInBuffer() )) != ERROR_SUCCESS )
            {
                TRACE(_T("SerialPortRxThreadFn : Serial port callback function failed.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), dwRetVal, __WFILE__, __LINE__);
                return dwRetVal;
            }
        }

        if ( !::ResetEvent( pHandles[1] ) )
        {
            TRACE(_T("SerialPortRxThreadFn : Failed to reset the OVERLAPPED structure event.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
            return ::GetLastError();
        }
        break;

    default:
        // Do nothing.
        break;
    }
}

::CloseHandle( s_ov.hEvent );

return ERROR_SUCCESS;

呼び出し元の行にブレークポイントを設定すると、ReadFileすべてが期待どおりに機能し、PC はコールバック関数に入ります。ただし、ブレークポイントを次の行に設定すると、dwWrittenがゼロと評価され、ゼロになり、式が TRUE として評価され、ループが終了します。PC がコールバックに到達することはありません。私は何を間違っていますか?ありがとう。

4

4 に答える 4

2

私は Win32 API の専門家ではありませんが、タイミングの問題のように思えます (ハイゼンバグの一般的な原因です) ReadFile。デバッガーに侵入すると、データが到着するのに十分な一時停止が得られる可能性があるため、再開/ステップオーバーReadFileすると成功します。

イベントをトリガーできるデータの到着以外にも多くのことがあります。dwEventMask私の仮説が正しいかどうかを確認するためにあなたをチェックしたいかもしれません.

于 2010-12-08T23:07:28.360 に答える
1

このコードを見るのはかなり辛いです、それのいくつかを書きました。その冗長性は、まあ、他の誰かのクラスライブラリに固執するのが最善です。いくつかの危険信号。WaitCommEvent()の完了は、ReadFile()を呼び出すことができることを意味すると想定します。通常、使用したイベントマスクは表示されませんが、シリアルポートが何かを伝えたい理由は他にもたくさんあります。もう1つの問題は、WaitCommEventがすぐに完了する可能性があることです。それは珍しいことではありませんが、受信バッファで利用可能なものです。

このコードをどこかから盗む、それはハードコードです。できました。

于 2010-12-08T23:39:49.793 に答える
0

WaiCommEvent のドキュメントには、待機関数 (WaitForMultipleEObjects(...) など) を使用した後、GetOverlappedResult(...) 関数を使用して操作の結果を取得することが記載されています。Read\Write-File(...) は必要ありません。

于 2010-12-08T23:18:00.620 に答える
0

非同期でデータを読み取るために通信イベントは必要ありません。を呼び出すだけReadFileで「エラー」が発生ERROR_IO_PENDINGし、データが到着するとイベントが通知され、バイト数を取得できますGetOverlappedResult。データは最初に に提供したバッファにありますReadFile

于 2010-12-08T23:43:31.260 に答える