在 C 語言中使用互斥鎖
本文將介紹幾種在 C 語言中使用互斥鎖的方法。
使用 pthread_mutex_t
型別和 pthread_mutex_lock
函式來守護程式碼的關鍵部分
執行緒共享地址空間,這意味著對全域性變數等共享資料的修改必須同步,否則,將出現不正確的程式行為。請注意,下面的程式碼用 pthread_create
呼叫建立了 4 個額外的執行緒,並傳遞 func3
作為它們執行的起點。func3
在 10000 次迭代 for
迴圈中逐一修改全域性變數 shared
。因此,如果四個執行緒分別將 shared
的值遞增 10000,程式應該輸出 40000。
如果執行下面的程式碼,結果將是某個隨機整數,但不是 40000。這種行為一般被歸為競賽條件,意味著給定的執行緒在訪問共享變數時沒有相互協商即同步。即,往往當它們執行迴圈
交錯時,對共享變數的訪問和儲存達到不一致,最後得出錯誤的和。
多個執行緒修改記憶體中同一個物件的程式碼部分稱為關鍵部分。一般來說,關鍵部分應該用某種型別的鎖來保護,迫使其他執行緒等到當前執行緒完成執行,並確保它們都能得到正確的增量值。Mutex 是其中一種鎖型別,可以利用它來保護關鍵部分,就像 func3
中的這個 for
迴圈一樣。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.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_lock
和 pthread_mutex_unlock
函式。pthread_mutex_lock
鎖定作為唯一引數傳遞的 mutex 物件。如果互斥鎖已經被鎖定,呼叫執行緒會被阻塞,直到互斥鎖變得可用。應該呼叫 pthread_mutex_unlock
來解鎖互斥鎖。如果有執行緒在同一個互斥鎖上等待,則由排程策略決定哪個執行緒獲得物件鎖。最後,我們對四個執行緒中的每一個執行緒都呼叫 pthread_join
,並列印出整數-shared
,在這種情況下,它應該有正確的值儲存。
#include <stdio.h>
#include <stdlib.h>
#include <pthread.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
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn