在 C 語言中使用互斥鎖

Jinku Hu 2023年10月12日
在 C 語言中使用互斥鎖

本文將介紹幾種在 C 語言中使用互斥鎖的方法。

使用 pthread_mutex_t 型別和 pthread_mutex_lock 函式來守護程式碼的關鍵部分

執行緒共享地址空間,這意味著對全域性變數等共享資料的修改必須同步,否則,將出現不正確的程式行為。請注意,下面的程式碼用 pthread_create 呼叫建立了 4 個額外的執行緒,並傳遞 func3 作為它們執行的起點。func3 在 10000 次迭代 for 迴圈中逐一修改全域性變數 shared。因此,如果四個執行緒分別將 shared 的值遞增 10000,程式應該輸出 40000。

如果執行下面的程式碼,結果將是某個隨機整數,但不是 40000。這種行為一般被歸為競賽條件,意味著給定的執行緒在訪問共享變數時沒有相互協商即同步。即,往往當它們執行迴圈交錯時,對共享變數的訪問和儲存達到不一致,最後得出錯誤的和。

多個執行緒修改記憶體中同一個物件的程式碼部分稱為關鍵部分。一般來說,關鍵部分應該用某種型別的鎖來保護,迫使其他執行緒等到當前執行緒完成執行,並確保它們都能得到正確的增量值。Mutex 是其中一種鎖型別,可以利用它來保護關鍵部分,就像 func3 中的這個 for 迴圈一樣。

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;

void* func3(void* param) {
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

輸出:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
30384

在這種情況下,我們將利用 POSIX 執行緒庫及其內建的 pthread_mutex_t 型別。pthread_mutex_t 型別變數通常被宣告為 static 儲存持續時間。互斥鎖只能在使用前應該只初始化一次。當互斥鎖被宣告為 static 時,應該使用 PTHREAD_MUTEX_INITIALIZER 巨集來初始化它。當互斥鎖被初始化後,執行緒就可以相應地使用 pthread_mutex_lockpthread_mutex_unlock 函式。pthread_mutex_lock 鎖定作為唯一引數傳遞的 mutex 物件。如果互斥鎖已經被鎖定,呼叫執行緒會被阻塞,直到互斥鎖變得可用。應該呼叫 pthread_mutex_unlock 來解鎖互斥鎖。如果有執行緒在同一個互斥鎖上等待,則由排程策略決定哪個執行緒獲得物件鎖。最後,我們對四個執行緒中的每一個執行緒都呼叫 pthread_join,並列印出整數-shared,在這種情況下,它應該有正確的值儲存。

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

#ifndef NUM_THREADS
#define NUM_THREADS 4
#endif

int shared = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* func3(void* param) {
  pthread_mutex_lock(&mutex);
  printf("Incrementing the shared variable...\n");
  for (int i = 0; i < 10000; ++i) {
    shared += 1;
  }
  pthread_mutex_unlock(&mutex);
  return 0;
}

int main() {
  pthread_t threads[NUM_THREADS];

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_create(&threads[i], NULL, func3, NULL);
  }

  for (int i = 0; i < NUM_THREADS; ++i) {
    pthread_join(threads[i], NULL);
  }

  printf("%d\n", shared);
  exit(EXIT_SUCCESS);
}

輸出:

Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
Incrementing the shared variable...
40000
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 創辦人。Jinku 在機器人和汽車行業工作了8多年。他在自動測試、遠端測試及從耐久性測試中創建報告時磨練了自己的程式設計技能。他擁有電氣/ 電子工程背景,但他也擴展了自己的興趣到嵌入式電子、嵌入式程式設計以及前端和後端程式設計。

LinkedIn Facebook