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

C語言多線程協作實戰:條件變量實現生產者-消費者模型

     編輯:關於C

項目背景

本示例演示如何使用 POSIX 線程庫(pthread)構建一個多線程協作程序:多個計算線程並行生成數列項(1/i),兩個消費線程分別採用超時等待與無限等待兩種策略消費數據,完成不同的累加運算。程序輸出詳細記錄了線程間的同步交互過程,是學習條件變量、互斥鎖、線程同步的優秀實戰教材。

核心同步機制

共享數據結構

  • myjg[]:雙重用途數組。myjg[0] 存儲「已計算到的索引 i」,myjg[1..max] 存儲對應的 1/i 值。
  • isend:標誌位,指示計算是否結束。
  • eventlock (pthread_mutex_t):保護共享數據的互斥鎖。
  • myevent (pthread_cond_t):條件變量,用於線程間發送「新數據就緒」信號。

計算線程 (mycomp)

線程池中每個線程循環執行:

  1. 加鎖,檢查 isend 若結束則退出。
  2. 從 myjg[0] 取得當前索引 i,若 i < max 則遞增並寫回。
  3. 計算 1.0/i 存入 myjg[i],打印進度。
  4. 若達到 max,設置 isend=1,發送 pthread_cond_signal 通知一個等待線程,隨後 sleep(2) 後退出。
  5. 每計算 MAXTDS(線程池大小)個數,發送 pthread_cond_broadcast 喚醒所有消費線程,並 sleep(3) 模擬間歇。

消費線程 1:超時等待累加 (myprint1)

採用 pthread_cond_timedwait,設置 1 秒超時:

  • 超時返回 ETIMEDOUT 時打印 "time out",繼續下一輪等待,不阻塞。
  • 收到信號 (rc==0) 時,讀取 myjg[0] 獲取最新索引 maxi,累加 curj..maxi 區間的值,打印累加過程與結果。
  • 循環直到 curj > max,輸出最終累加和。

消費線程 2:無限等待交替加減 (myprint2)

採用 pthread_cond_wait 永久阻塞等待信號:

  • 收到信號後,同樣讀取 maxi,但在區間內執行 jg += fh * myjg[curi],fh 在 1/-1 間翻轉,實現交替加減(1/1 - 1/2 + 1/3 - ...)。
  • 每輪處理完打印階段性結果,直到 curi > max。

主函數流程

  1. 初始化互斥鎖與條件變量。
  2. 讀取用戶輸入 max(≤1000)。
  3. 依次創建:消費線程1、消費線程2、5個計算線程(MAXTDS=5),每創建一個 sleep(1) 錯開啟動。
  4. 主線程 sleep 等待足夠時間,最後銷毀鎖退出。

運行輸出解讀

終端輸出清晰展示了:

  • 計算線程推進索引並推送數值("1/i finished,push ...")。
  • 消費線程1 因超時頻繁打印 "time out",收到廣播後批量累加。
  • 消費線程2 每次被喚醒即處理新區間,輸出交替加減的部分和。
  • 最終兩線程分別輸出「add finish」與「compute finish」總結果。

關鍵學習點

  1. 條件變量必須配合互斥鎖使用:wait 原子性地釋放鎖並阻塞,被喚醒後重新獲取鎖。
  2. signal vs broadcast:signal 喚醒一個線程(適合單消費者),broadcast 喚醒所有(適合多消費者或狀態變更)。
  3. 超時等待避免死等:timedwait 允許線程定期檢查其他條件,增強健壯性。
  4. 共享索引 myjg[0] 充當「生產進度游標」,消費者據此決定處理範圍,無需額外隊列結構。

此程序雖為教學演示,但完整呈現了生產者-消費者模型的核心同步邏輯,是掌握 C 多線程編程的寶貴案例。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved