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

Linux C 多線程生產者消費者模型完整實現:互斥鎖與條件變量實戰

     編輯:關於C語言

生產者消費者模型核心邏輯

經典並發模式:生產者向共享緩衝區放入數據,消費者從中取出處理。核心約束:

  • 緩衝區滿時生產者等待
  • 緩衝區空時消費者等待
  • 對緩衝區操作需互斥

Linux pthread 提供 pthread_mutex_t(互斥鎖)和 pthread_cond_t(條件變量)實現同步。

線程安全隊列實現


#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>

#define MAXLENGTH 10

typedef char *datatype;

typedef struct node {
    datatype name;
    struct node *next;
} node;

typedef struct queue {
    node *front, *rear;
    int len;
} queue;

void queue_init(queue *q) {
    q->front = q->rear = NULL;
    q->len = 0;
}

void queue_put(queue *q, datatype new_name) {
    node *mynode = malloc(sizeof(node));
    mynode->name = new_name;
    mynode->next = NULL;
    if (q->rear) q->rear->next = mynode;
    q->rear = mynode;
    if (q->front == NULL) q->front = mynode;
    q->len++;
}

datatype queue_get(queue *q) {
    node *mynode = q->front;
    datatype myname = mynode->name;
    q->front = q->front->next;
    q->len--;
    free(mynode);
    return myname;
}

void queue_print(queue *q) {
    node *tmp = q->front;
    while (tmp) {
        printf("%s ", tmp->name);
        tmp = tmp->next;
    }
    printf("\n");
}

同步機制:互斥鎖 + 雙條件變量


// 全局同步對象
pthread_cond_t q_not_full = PTHREAD_COND_INITIALIZER;
pthread_cond_t q_not_empty = PTHREAD_COND_INITIALIZER;
pthread_mutex_t qlock = PTHREAD_MUTEX_INITIALIZER;

void *producer(void *arg) {
    queue *qt = (queue *)arg;
    while (1) {
        pthread_mutex_lock(&qlock);
        
        // 緩衝區滿,等待 not_full 信號
        while (qt->len >= MAXLENGTH) {
            pthread_cond_wait(&q_not_full, &qlock);
        }
        
        queue_put(qt, "*");  // 生產數據
        printf("生產: 長度=%d\n", qt->len);
        
        pthread_mutex_unlock(&qlock);
        pthread_cond_signal(&q_not_empty);  // 通知消費者
        
        usleep(100000);  // 模擬生產耗時
    }
    return NULL;
}

void *consumer(void *arg) {
    queue *qt = (queue *)arg;
    while (1) {
        pthread_mutex_lock(&qlock);
        
        // 緩衝區空,等待 not_empty 信號
        while (qt->len <= 0) {
            pthread_cond_wait(&q_not_empty, &qlock);
        }
        
        datatype name = queue_get(qt);  // 消費數據
        printf("消費: %s, 剩餘長度=%d\n", name, qt->len);
        
        pthread_mutex_unlock(&qlock);
        pthread_cond_signal(&q_not_full);  // 通知生產者
        
        usleep(150000);  // 模擬消費耗時
    }
    return NULL;
}

關鍵同步細節解析

  1. while 而非 if:pthread_cond_wait 可能發生虛假喚醒,必須用 while 重新檢查條件。
  2. 鎖的範圍:鎖保護「檢查條件 → 修改隊列」的原子性,cond_wait 內部自動釋放鎖並休眠,喚醒後重新獲取鎖。
  3. 信號 vs 廣播:單生產單消費用 signal 足夠;多生產/多消費建議 broadcast 避免信號丟失。
  4. 初始化:靜態初始化器 PTHREAD_COND_INITIALIZER、PTHREAD_MUTEX_INITIALIZER 簡化代碼。

主程序與編譯運行


int main() {
    pthread_t tid1, tid2;
    queue *q = malloc(sizeof(queue));
    queue_init(q);
    
    pthread_create(&tid1, NULL, producer, q);
    pthread_create(&tid2, NULL, consumer, q);
    
    // 運行 5 秒後退出(演示用)
    sleep(5);
    printf("主線程退出\n");
    return 0;  // 實際項目需優雅關閉:設置標誌、broadcast、join
}

# 編譯(必須鏈接 pthread)
gcc -Wall -O2 -o prod_cons prod_cons.c -lpthread

# 運行
./prod_cons

生產級優化建議

  • 優雅關閉:引入 volatile bool shutdown,生產者/消費者檢查後 break,主線程 pthread_cond_broadcast 喚醒所有等待線程,隨後 pthread_join 回收。
  • 無鎖隊列:高性能場景可用環形緩衝區 + 原子操作(__atomic / C11 atomic)實現無鎖 SPSC 隊列。
  • 批量操作:減少鎖爭用,單次鎖內處理多個元素。
  • 優先級反轉:實時系統需設置 mutex 屬性 PTHREAD_PRIO_INHERIT。
  • 內存池:頻繁 malloc/free 可改用對象池減少系統調用。

常見錯誤排查

現象可能原因排查方法
程序掛起死鎖/信號未發送GDB 附加查看線程棧,檢查 cond_wait/cond_signal 配對
數據競爭鎖保護範圍不足ThreadSanitizer (-fsanitize=thread) 檢測
內存洩漏節點未 freeValgrind --leak-check=full
段錯誤空指針解引用GDB bt,檢查 queue_get 前是否判空
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved