首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ 串口通訊多線程架構設計:重疊 I/O、同步物件與事件驅動

     編輯:VC 教學

前言

Windows 串口通訊屬 I/O 密集型任務,單線程阻塞式讀寫會嚴重拖慢主執行緒回應。採用多線程 + 重疊 I/O (Overlapped I/O) 架構,可實現非阻塞收發、多埠並行監控與高效率事件驅動處理。

VC++ 多線程基礎

  • 使用者介面線程:擁有訊息迴圈,處理 UI 互動。
  • 工作者線程:無訊息迴圈,專職背景運算、I/O 處理。
  • 統一由 AfxBeginThread 建立,回傳 CWinThread*。

同步物件選擇指南

物件適用場景特性
CSemaphore限制共享資源同時存取數量 (如連線池)計數訊號
CMutex互斥存取關鍵區段 (單一執行緒)跨進程可用
CEvent執行緒間事件通知 (資料就緒、結束信號)手動/自動重設
CCriticalSection進程內程式碼區段互斥 (效能最佳)僅進程內有效

等待函數

  • WaitForSingleObject(h, INFINITE):單一物件等待。
  • WaitForMultipleObjects(n, handles, FALSE, INFINITE):多物件等待 (任一觸發即返回)。

重疊 I/O 核心流程

  1. CreateFile(..., FILE_FLAG_OVERLAPPED, ...) 開啟序列埠。
  2. 建立 OVERLAPPED 結構,hEvent = CreateEvent(...)。
  3. ReadFile/WriteFile 立即返回,I/O 在背景進行。
  4. WaitCommEvent 監控通訊事件 (RXCHAR, TXEMPTY...)。
  5. 工作者線程 WaitForMultipleObjects 等待 OVERLAPPED.hEvent、關閉事件、自訂事件。

關鍵程式碼實作

1. 序列埠初始化


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

2. 監控工作者線程


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

3. 主程式啟動線程


m_bRunning = TRUE;
AfxBeginThread(CommThread, this);

效能優化建議

  • 接收緩衝區設定較大 (SetCommConfig 或註冊表)。
  • 發送採用非同步佇列,工作者線程批次 WriteFile。
  • 關鍵區段保護共用資料結構 (環狀緩衝區、狀態旗標)。
  • 錯誤處理完善:ClearCommError 取得錯誤碼並重設。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved