Question

Mon application utilise un thread séparé pour traiter les données série reçues de manière asynchrone. Le PC reçoit dans le receive-gestionnaire comme prévu, mais de là les choses vont bizarre.

Ceci est ma fonction de fil:

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

Si je mets mon point d'arrêt sur la ligne appelant tout ReadFile fonctionne comme je le pense, et le PC entre dans la fonction de rappel. Cependant, si je mets mon point d'arrêt à la ligne suivante, où dwWritten est évalué pour zéro, il est égal à zéro, l'expression est TRUE, et les sorties en boucle; le PC ne fait jamais au rappel. Qu'est-ce que je fais mal? Merci.

Était-ce utile?

La solution

Je ne suis pas expert sur l'API Win32, mais il est certain des sons comme un problème de synchronisation (ce qui est une cause fréquente de bug logiciel inhabituel.) LET dire de moment où vous arrivez à ReadFile, il n'y a pas de données à lire. Pénétrer dans le débogueur pourrait lui donner assez d'une pause pour que les données arrivent, donc quand vous reprenez / étape sur ReadFile, il réussit.

Il y a beaucoup de choses autres que l'arrivée des données qui pourraient déclencher l'événement. Vous pouvez vérifier votre dwEventMask pour voir si mon hypothèse est vraie.

Autres conseils

Assez pénible à regarder ce code, écrit un peu. La verbosité est, bien, le meilleur coincé dans la bibliothèque de quelqu'un d'autre classe. Quelques drapeaux rouges. Vous supposez que les moyens d'achèvement WaitCommEvent () que vous pouvez appeler ReadFile (). Généralement pas, le masque d'événement que vous avez utilisé est pas visible, mais il y a beaucoup d'autres raisons que le port série veut vous dire quelque chose. Un autre problème est que WaitCommEvent peut compléter tout de suite. Il ne rare, quelque chose de disponible dans le tampon de réception.

Steal ce code de quelque part, il est difficile de code. Il a été fait.

La documentation WaiCommEvent indique que, après que vous avez utilisé une fonction d'attente (comme WaitForMultipleEObjects (...)), vous utilisez la fonction GetOverlappedResult (...) pour obtenir les résultats de votre opération. Il devrait y avoir pas besoin de lecture de fichier en écriture (...).

Vous n'avez pas besoin d'événements de comm pour lire les données de manière asynchrone. Il suffit d'appeler ReadFile, vous obtiendrez le ERROR_IO_PENDING « erreur », et lorsque les données arrivent l'événement sera signalé et vous pouvez alors obtenir le nombre d'octets GetOverlappedResult, les données seront dans le vous en mémoire tampon initialement fourni à ReadFile.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top