Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 線程同步:信號量機制深度解析與應用

編輯:Linux 教學

線程同步的本質

現實中,順序執行是常態:我完成,你才能接著做。程式設計同理,線程同步的核心是協調對共享資源(記憶體區域、全局變量)或臨界區的訪問順序。當共享資源同一時刻只能容忍單線程操作(特別是寫操作)時,必須引入同步機制。Linux 提供兩大主流方案:信號量與互斥量。本文聚焦信號量。

信號量核心概念

信號量是一種特殊變量,支持原子性的增減操作。即使多線程並發修改,系統保證操作依次進行,避免競態條件。普通變量在並發下會導致未定義行為。

按取值範圍分類:

  • 二進制信號量:僅 0/1,適合單線程獨佔資源場景(類似互斥量)。
  • 計數信號量:取值範圍較大,適合多實例資源池(如連接池、緩衝區槽位)。

核心 API 速查

函數功能關鍵參數
sem_init(sem, pshared, value)初始化信號量pshared=0 進程內共享;value 初始值
sem_wait(sem)原子減 1(P 操作)值 > 0 時立即返回;值 = 0 時阻塞等待
sem_post(sem)原子加 1(V 操作)喚醒等待線程(如有)
sem_getvalue(sem, &val)獲取當前值非標準 POSIX,Linux 支持
sem_destroy(sem)銷毀信號量若有線程等待則報錯

關鍵行為:sem_wait 會阻塞直到信號量值 ≥ 1,然後原子減 1 並繼續;sem_post 原子加 1 並喚醒一個等待線程(如有)。

實戰案例:主線程輸入、子線程轉大寫(信號量版)

設計邏輯:主線程初始化信號量為 0;讀取輸入後 sem_post;子線程 sem_wait 阻塞,被喚醒後處理數據,處理完畢再 sem_wait 等待下一次輸入。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>

void *threadFunc(void *arg);
sem_t sem;
#define WORK_SIZE 1024
char work_area[WORK_SIZE]; // 共享緩衝區

int main() {
    int res;
    pthread_t upperThread;
    void *threadRes;

    res = sem_init(&sem, 0, 0); // 初始值 0
    if (res != 0) { perror("Semaphore init failed"); exit(EXIT_FAILURE); }

    res = pthread_create(&upperThread, NULL, threadFunc, NULL);
    if (res != 0) { perror("Thread create failed"); exit(EXIT_FAILURE); }

    printf("Please input convert text, then enter 'end' to finish.\n");
    while (strncmp("end", work_area, 3) != 0) {
        fgets(work_area, WORK_SIZE, stdin);
        sem_post(&sem); // 輸入完成,釋放信號量
        int semValue = 0;
        sem_getvalue(&sem, &semValue);
        printf("Semaphore count: %d\n", semValue);
    }

    printf("\nWaiting for thread to finish...\n");
    res = pthread_join(upperThread, &threadRes);
    if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); }
    printf("Thread joined.\n");
    sem_destroy(&sem);
    exit(EXIT_SUCCESS);
}

void *threadFunc(void *arg) {
    sem_wait(&sem); // 等待主線程輸入
    int semValue = 0;
    sem_getvalue(&sem, &semValue);
    printf("Semaphore count: %d\n", semValue);

    while (strncmp("end", work_area, 3) != 0) {
        for (int i = 0; work_area[i] != '\0'; ++i) {
            if (work_area[i] >= 'a' && work_area[i] <= 'z')
                work_area[i] = work_area[i] - 32; // 轉大寫
        }
        printf("After converted: %s\n", work_area);
        sem_wait(&sem); // 再次阻塞,等待下一次輸入
    }
    pthread_exit(NULL);
}

關鍵差異與選型建議

特性互斥量信號量
核心目的互斥訪問臨界區同步協調、資源計數
所有權有擁有者(加鎖線程必須解鎖)無所有權(任意線程可 post)
適用場景保護共享數據結構生產者-消費者、資源池、事件通知
計數能力二元(鎖/解鎖)計數型,支持多實例

本例中,信號量單獨完成同步協調,但實際項目中常互斥量保護數據 + 信號量同步步驟組合使用(參考上一篇互斥量實戰代碼)。

Copyright © Windows教程網 All Rights Reserved