Windows 串口通訊屬 I/O 密集型任務,單線程阻塞式讀寫會嚴重拖慢主執行緒回應。採用多線程 + 重疊 I/O (Overlapped I/O) 架構,可實現非阻塞收發、多埠並行監控與高效率事件驅動處理。
AfxBeginThread 建立,回傳 CWinThread*。| 物件 | 適用場景 | 特性 |
|---|---|---|
CSemaphore | 限制共享資源同時存取數量 (如連線池) | 計數訊號 |
CMutex | 互斥存取關鍵區段 (單一執行緒) | 跨進程可用 |
CEvent | 執行緒間事件通知 (資料就緒、結束信號) | 手動/自動重設 |
CCriticalSection | 進程內程式碼區段互斥 (效能最佳) | 僅進程內有效 |
WaitForSingleObject(h, INFINITE):單一物件等待。WaitForMultipleObjects(n, handles, FALSE, INFINITE):多物件等待 (任一觸發即返回)。CreateFile(..., FILE_FLAG_OVERLAPPED, ...) 開啟序列埠。OVERLAPPED 結構,hEvent = CreateEvent(...)。ReadFile/WriteFile 立即返回,I/O 在背景進行。WaitCommEvent 監控通訊事件 (RXCHAR, TXEMPTY...)。WaitForMultipleObjects 等待 OVERLAPPED.hEvent、關閉事件、自訂事件。
BOOL CCommPort::InitComm()
{
m_hComm = CreateFile(_T("COM1"),
GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, 0);
if (m_hComm == INVALID_HANDLE_VALUE) return FALSE;
COMMTIMEOUTS ct = {0};
ct.ReadIntervalTimeout = 1000;
ct.ReadTotalTimeoutMultiplier = 500;
ct.ReadTotalTimeoutConstant = 5000;
ct.WriteTotalTimeoutMultiplier = 500;
ct.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts(m_hComm, &ct);
PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
return TRUE;
}
UINT CCommPort::CommThread(LPVOID pParam)
{
CCommPort* pThis = (CCommPort*)pParam;
OVERLAPPED ov = {0};
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
pThis->m_ov = ov;
HANDLE hEvents[4] = { ov.hEvent, pThis->m_hRxEvent, pThis->m_hTxEvent, pThis->m_hCloseEvent };
while (pThis->m_bRunning)
{
DWORD dwEvent;
if (!WaitCommEvent(pThis->m_hComm, &dwEvent, &ov))
{
if (GetLastError() == ERROR_IO_PENDING)
{
DWORD idx = WaitForMultipleObjects(4, hEvents, FALSE, INFINITE);
switch (idx)
{
case WAIT_OBJECT_0: // OVERLAPPED 完成
// 處理讀寫完成
break;
case WAIT_OBJECT_0 + 1: // 接收事件
pThis->HandleRx();
break;
case WAIT_OBJECT_0 + 2: // 發送事件
pThis->HandleTx();
break;
case WAIT_OBJECT_0 + 3: // 關閉事件
return 0;
}
}
}
}
CloseHandle(ov.hEvent);
return 0;
}
m_bRunning = TRUE;
AfxBeginThread(CommThread, this);
SetCommConfig 或註冊表)。WriteFile。ClearCommError 取得錯誤碼並重設。