互斥量是多線程編程中實現同步訪問的核心機制,它允許程式鎖定特定代碼段或共享資源,確保同一時刻僅有一個線程能夠訪問。本質上,互斥量與信號量同屬 P/V 操作體系:進入臨界區前加鎖(P 操作),退出後解鎖(V 操作)。
| 函數 | 功能 | 返回值 |
|---|---|---|
pthread_mutex_init() | 初始化互斥量 | 成功返回 0,失敗返回錯誤碼(不設 errno) |
pthread_mutex_lock() | 加鎖(阻塞等待) | 同上 |
pthread_mutex_trylock() | 非阻塞嘗試加鎖 | 同上,鎖已被佔用時立即返回 EBUSY |
pthread_mutex_unlock() | 解鎖 | 同上 |
pthread_mutex_destroy() | 銷毀互斥量 | 同上 |
需求:主線程持續從標準輸入讀取字符串,輸入 "end" 終止;子線程將輸入轉為大寫並輸出。使用互斥量保護共享緩衝區,信號量協調線程切換。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
void *threadFunc(void *arg);
pthread_mutex_t work_mutex;
sem_t sem;
#define WORK_SIZE 1024
char work_area[WORK_SIZE];
int main() {
int res;
pthread_t thread1;
void *threadRes;
// 初始化互斥量
res = pthread_mutex_init(&work_mutex, NULL);
if (res != 0) { perror("Mutex init failed"); exit(EXIT_FAILURE); }
// 初始化信號量(初值 0)
res = sem_init(&sem, 0, 0);
if (res != 0) { perror("Semaphore init failed"); exit(EXIT_FAILURE); }
// 創建子線程
res = pthread_create(&thread1, NULL, threadFunc, NULL);
if (res != 0) { perror("Thread create failed"); exit(EXIT_FAILURE); }
printf("Input some text. Enter 'end' to finish.\n");
pthread_mutex_lock(&work_mutex);
while (strncmp(work_area, "end", 3) != 0) {
fgets(work_area, WORK_SIZE, stdin);
pthread_mutex_unlock(&work_mutex);
sem_wait(&sem); // 等待子線程處理完畢
pthread_mutex_lock(&work_mutex);
}
pthread_mutex_unlock(&work_mutex);
printf("\nWaiting for thread to finish...\n");
res = pthread_join(thread1, &threadRes);
if (res != 0) { perror("Thread join failed"); exit(EXIT_FAILURE); }
printf("Thread joined.\n");
pthread_mutex_destroy(&work_mutex);
sem_destroy(&sem);
exit(EXIT_SUCCESS);
}
void *threadFunc(void *arg) {
pthread_mutex_lock(&work_mutex);
while (strncmp(work_area, "end", 3) != 0) {
if (work_area[0] != '\0') {
for (int i = 0; work_area[i] != '\0'; ++i) {
if (work_area[i] >= 'a' && work_area[i] <= 'z')
work_area[i] -= 'a' - 'A';
}
printf("After converted: %s\n", work_area);
sem_post(&sem); // 通知主線程可繼續讀取
memset(work_area, 0, sizeof(work_area));
}
pthread_mutex_unlock(&work_mutex);
sleep(1);
pthread_mutex_lock(&work_mutex);
}
pthread_mutex_unlock(&work_mutex);
sem_post(&sem);
pthread_exit(NULL);
}
sleep() 在鎖外)。strncmp 比較 "end" 需確保緩衝區以空字符結尾,fgets 保留換行符,實際項目中需去除。多線程同步之難,在於人腦天然單線程思維,需通過大量實踐建立並發直覺。「左手畫圓右手畫方」的協調,唯有多思、多寫、多填坑方能精進。