串行端口接收线程的行为不如预期-C ++
-
10-10-2019 - |
题
我的应用程序使用一个单独的线程来处理接收的串行数据。 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
评估为零,为零,表达式评估为真实,并且循环退出; PC永远不会到达回调。我究竟做错了什么?谢谢。
解决方案
我不是Win32 API的专家,但听起来确实是一个计时问题(这是 海森伯斯。)假设您到达时 ReadFile
, ,没有数据要读取。闯入调试器可能会给它足够的停顿以使数据到达,因此,当您恢复/逐步时 ReadFile
, ,成功。
除了可能触发事件的数据的到来之外,还有很多事情。您可能想检查您的 dwEventMask
看看我的假设是否正确。
其他提示
观看此代码非常痛苦,写了一些代码。它的详细性最好被困在别人的班级图书馆中。几个危险信号。您假设WaitCommevent()完成意味着您可以调用ReadFile()。通常,您使用的事件面具并不可见,但是串行端口还有很多其他原因想告诉您一些事情。另一个问题是WaitCommevent可能会立即完成。它并不罕见,接收缓冲区中可用的东西。
从某个地方窃取此代码,这是硬码。已经完成了。
WAICOMMEVENT的文档指出,在使用Wait功能(例如WaitformultPirultEobjects(...))之后,您使用GetoverLappedResult(...)函数来获取操作的结果。不需要阅读写入文件(...)。
您不需要通讯事件即可不同步读取数据。只是打电话 ReadFile
, ,您将获得“错误” ERROR_IO_PENDING
, ,当数据到达时,将发出信号,然后您可以获取字节数 GetOverlappedResult
, ,数据将在您最初提供给的缓冲区中 ReadFile
.