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

POSIX線程信號量API詳解:sem_init、sem_wait、sem_post、sem_destroy

     編輯:關於C語言

POSIX線程信號量API詳解:sem_init、sem_wait、sem_post、sem_destroy

POSIX信號量(<semaphore.h>)是線程同步的核心工具。本文詳細講解四大核心函數的原型、參數、返回值、使用模式及完整示例。

一、數據類型

sem_t sem; // 信號量對象,視為不透明類型,僅通過指針操作

二、核心API

1. sem_init — 初始化


int sem_init(sem_t *sem, int pshared, unsigned int value);
參數說明
sem信號量對象指針
pshared0:線程間共享(同一進程);非0:進程間共享(需放在共享內存區)
value初始值(可用資源數/信號計數)
  • 成功返回 0,失敗返回 -1 並設置 errno。
  • 線程間同步通常 pshared=0。

2. sem_destroy — 銷毀


int sem_destroy(sem_t *sem);
  • 釋放信號量佔用的內核資源。
  • 只能銷毀已初始化且無線程阻塞在其上的信號量,否則行為未定義。
  • 成功返回 0,失敗返回 -1。

3. sem_wait — P操作 (等待/獲取)


int sem_wait(sem_t *sem);
  • 原子地將信號量值 -1。
  • 若結果 ≥ 0:立即返回,獲得資源/許可。
  • 若結果 < 0:阻塞當前線程,直到信號量 > 0 被喚醒。
  • 成功返回 0,失敗返回 -1(如被信號中斷 EINTR)。

4. sem_post — V操作 (釋放/通知)


int sem_post(sem_t *sem);
  • 原子地將信號量值 +1。
  • 若有線程阻塞在 sem_wait,喚醒其中一個(通常優先級最高者)。
  • 成功返回 0,失敗返回 -1。
  • 可在信號處理函數中安全調用(少數異步信號安全函數之一)。

三、使用模式

模式1:互斥鎖(二值信號量,初值1)


sem_t mutex;
sem_init(&mutex, 0, 1); // 初值1

// 臨界區
sem_wait(&mutex); // 加鎖
// ... 訪問共享資源 ...
sem_post(&mutex); // 解鎖

sem_destroy(&mutex);

模式2:生產者-消費者(計數信號量 + 互斥鎖)


#define BUF_SIZE 10
int buffer[BUF_SIZE];
int in=0, out=0;

sem_t empty, full, mutex;

void init() {
    sem_init(&empty, 0, BUF_SIZE); // 空槽位數
    sem_init(&full, 0, 0);         // 滿槽位數
    sem_init(&mutex, 0, 1);        // 緩衝區互斥
}

void producer(int item) {
    sem_wait(&empty);      // 等待空槽
    sem_wait(&mutex);      // 鎖緩衝區
    buffer[in] = item;
    in = (in+1)%BUF_SIZE;
    sem_post(&mutex);      // 解鎖
    sem_post(&full);       // 通知有產品
}

int consumer() {
    sem_wait(&full);       // 等待產品
    sem_wait(&mutex);      // 鎖緩衝區
    int item = buffer[out];
    out = (out+1)%BUF_SIZE;
    sem_post(&mutex);      // 解鎖
    sem_post(&empty);      // 通知有空槽
    return item;
}

模式3:線程同步/事件通知(初值0)


sem_t ready;
sem_init(&ready, 0, 0);

// 線程A:準備數據
prepare_data();
sem_post(&ready); // 通知數據就緒

// 線程B:等待數據
sem_wait(&ready); // 阻塞直到A發信號
use_data();

四、進階API(補充)

  • sem_trywait:非阻塞嘗試獲取,不可用即返回 EAGAIN。
  • sem_timedwait:帶超時等待(絕對時間 struct timespec)。
  • sem_getvalue:獲取當前值(調試用,非同步安全)。

五、編譯鏈接


gcc -pthread -o prog prog.c  // 必須鏈接 pthread 庫 (包含信號量實現)

六、常見錯誤

  1. 忘記 sem_init 直接使用 → 未定義行為。
  2. pshared 設置錯誤:線程間用非0,進程間用0。
  3. 銷毀時仍有線程阻塞 → 崩潰/死鎖。
  4. sem_post 過多導致信號量溢出(超過 SEM_VALUE_MAX)。
  5. 在臨界區內調用阻塞函數(I/O、sleep)導致性能下降或死鎖。

POSIX信號量功能強大、語義清晰,是構建生產者消費者、資源池、事件通知等並發模式的利器。熟練掌握 init/wait/post/destroy 四大件,配合互斥量保護共享數據結構,即可駕馭大多數線程同步場景。

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