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

多線程同步機制:臨界區實戰測試與效能分析

     編輯:關於VC++

引言

在多線程程式設計中,共享資源的存取同步是核心課題。本文透過具體測試案例,展示臨界區在保護檔案寫入操作時的同步效果,並分析同步與非同步模式下的資料完整性差異與效能代價。

測試場景設計

  • 線程數量:10 個工作線程
  • 共享資源:單一文字檔案 (1.txt)
  • 操作內容:每個線程寫入 100 筆記錄,包含線程 ID、時間戳記,以雙虛線分隔
  • 測試模式:分別執行「無同步」與「臨界區同步」兩組實驗

核心程式碼實現

線程安全檔案類別

class CMyFile {
public:
    CMyFile() { InitializeCriticalSection(&cs); }
    ~CMyFile() { DeleteCriticalSection(&cs); }

    void MsgLog(char* buffer, int length, int wait) {
        static int i = 0;
        CString seq;
        seq.Format("%d#", i++);

        if (m_bSync) EnterCriticalSection(&cs);

        fwrite("\n", 1, 1, fp);
        fwrite(seq + CString('-', 50), 52, 1, fp);
        fwrite("\n", 1, 1, fp);
        fwrite(buffer, length, 1, fp);
        Sleep(wait);  // 模擬處理延遲
        fwrite("\n", 1, 1, fp);
        fwrite(seq + CString('-', 50), 52, 1, fp);
        fflush(fp);

        if (m_bSync) LeaveCriticalSection(&cs);
    }

    bool OpenFile(CString filename, bool bSync) {
        m_bSync = bSync;
        fp = fopen(filename, "wt");
        return fp != NULL;
    }
    void CloseFile() { if (fp) fclose(fp); }

protected:
    CRITICAL_SECTION cs;
    FILE* fp = nullptr;
    CString m_filename;
    bool m_bSync = false;
};

線程函數與啟動邏輯

UINT ThreadFunc(LPVOID p) {
    CMyFile* file = (CMyFile*)p;
    long tid = AfxGetThread()->m_nThreadID;
    CString prefix;
    prefix.Format("thread %d", tid);

    for (int i = 0; i < 100; i++) {
        CTime now = CTime::GetCurrentTime();
        CString log = now.Format("%y-%m-%d %H:%M:%S") + "--------->" + prefix;
        file->MsgLog(log.GetBuffer(), log.GetLength(), tid / 100);
    }
    return 1;
}

void CBDlg::OnButtonTest() {
    CMyFile file;
    file.OpenFile("1.txt", m_sync.GetCheck());  // 由 UI 決定是否同步

    CWinThread* threads[10];
    HANDLE handles[10];
    for (int i = 0; i < 10; i++) {
        threads[i] = AfxBeginThread(ThreadFunc, &file);
        Sleep(10);  // 錯開啟動時間
        handles[i] = threads[i]->m_hThread;
    }
    WaitForMultipleObjects(10, handles, TRUE, INFINITE);
    file.CloseFile();
    AfxMessageBox("ok");
}

測試結果分析

模式資料完整性輸出順序執行時間
無同步虛線配對錯亂、內容交疊亂序較快
臨界區同步每筆記錄虛線完美配對依線程取得鎖順序排列顯著增加

關鍵結論

  1. 同步必要性:臨界區確保同一時間僅有一個線程執行寫入序列,保證邏輯原子性
  2. 效能代價:鎖競爭導致線程等待,總執行時間隨線程數與臨界區長度成正比增長
  3. 適用場景:適合短小、高頻率的共享資源存取;長耗時操作應考慮無鎖資料結構或非同步設計

進階建議

  • 使用 CSingleLock/CMultiLock 管理鎖生命週期,避免例外導致死鎖
  • 縮小臨界區範圍:僅保護必要的共享操作,將格式化字串等非共享運算移出鎖外
  • 考慮 SRWLOCK (Vista+) 或無鎖佇列 以提升高併發效能
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved