Domanda

La mia applicazione utilizza un thread separato per la gestione di dati seriali ricevuti in modo asincrono. Il PC entra nella ricezione-handler come previsto, ma da lì le cose vanno strano.

Questa è la mia funzione di discussione:

// 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;

Se ho impostato il mio punto di interruzione sulla linea chiamando ReadFile tutto funziona come mi aspetto, e il PC entra nella funzione di callback. Tuttavia, se impostato il mio punto di interruzione alla riga successiva, dove dwWritten viene valutata per zero, è zero, gli Valuta expression come TRUE, e il ciclo termina; il PC non viene mai al callback. Che cosa sto facendo di sbagliato? Grazie.

È stato utile?

Soluzione

Non sono un esperto sulle API Win32, ma suona certo, come un problema di temporizzazione (che è una causa comune di heisenbug .) diciamo di Let per il momento si arriva a ReadFile, non ci sono dati da leggere. Ultime in debugger potrebbe dargli abbastanza di una pausa per i dati per arrivare, in modo che quando si riprende / step sopra ReadFile, riesce.

Ci sono un sacco di altre cose che l'arrivo dei dati che potrebbero innescare l'evento. Si consiglia di controllare il vostro dwEventMask per vedere se la mia ipotesi è vera.

Altri suggerimenti

abbastanza doloroso da guardare questo codice, scritto un po '. La verbosità di esso è, beh, meglio bloccato nella libreria di classi di qualcun altro. Un paio di bandiere rosse. L'utente si assume che i WaitCommEvent () mezzi di completamento che è possibile chiamare ReadFile (). Non tipicamente, la maschera degli eventi che hai usato non è visibile, ma ci sono un sacco di altri motivi che la porta seriale vuole dirti una cosa. Un altro problema è che WaitCommEvent potrebbe completare subito. E non di rado fa, qualcosa a disposizione nel buffer di ricezione.

Ruba questo codice da qualche parte, è codificare. E 'stato fatto.

La documentazione di WaiCommEvent afferma che dopo che hai usato una funzione di attesa (come WaitForMultipleEObjects (...)), si utilizza la funzione GetOverlappedResult (...) per ottenere i risultati della vostra attività. Non ci dovrebbe essere bisogno di Read \ Write-File (...).

Non è necessario eventi comm per leggere i dati in modo asincrono. Proprio ReadFile chiamata, si otterrà il ERROR_IO_PENDING "errore", e quando arriva dati viene segnalata l'evento e quindi è possibile ottenere il numero di byte GetOverlappedResult, i dati saranno nel buffer originariamente forniti a ReadFile.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top