天天看點

C語言編寫多線程,什麼時候要使用互斥鎖?為什麼要使用互斥鎖?

作者:軟硬門徒

在多線程程式設計中,當多個線程同時通路共享資源(如變量、檔案等)時,會出現競态條件(Race Condition)問題,導緻程式的行為不可預測。為了避免這種問題,需要使用互斥鎖來保護共享資源的通路。

互斥鎖是一種線程同步機制,它保證同一時刻隻有一個線程可以通路共享資源,其他線程需要等待該線程釋放鎖才能繼續通路。在C語言中,可以使用标準庫提供的pthread_mutex_t結構體來實作互斥鎖。

在哪些情況下需要使用互斥鎖呢?一般來說,隻有在多個線程同時通路共享資源時才需要使用互斥鎖。以下是一些常見的情況:

  1. 多個線程同時通路同一個全局變量或靜态變量。
  2. 多個線程同時通路同一個動态配置設定的記憶體塊。
  3. 多個線程同時通路同一個檔案或網絡套接字。
  4. 多個線程同時通路同一個資料結構,如連結清單或樹。

需要注意的是,過多地使用互斥鎖可能會導緻性能問題。是以,在使用互斥鎖時,需要權衡程式的正确性和性能開銷,盡可能減少鎖的使用次數。

C語言編寫多線程,什麼時候要使用互斥鎖?為什麼要使用互斥鎖?

假設有兩個線程 A 和 B,它們需要同時通路一個共享資源:一個全局變量 x。線程 A 需要讀取 x 的值并将其加 1,線程 B 需要讀取 x 的值并将其減 1。

如果不使用互斥鎖,可能會出現以下情況:

  1. 線程 A 讀取 x 的值為 n,然後将其加 1,得到 n+1。
  2. 線上程 A 執行完加 1 操作之前,線程 B 讀取 x 的值為 n,然後将其減 1,得到 n-1。
  3. 線程 A 将 n+1 寫回到 x 中,x 的值變成了 n+1。
  4. 線程 B 将 n-1 寫回到 x 中,x 的值變成了 n-1,而不是原本的 n。

為了避免這種競态條件問題,可以使用互斥鎖來保護 x 的通路。具體地,在通路 x 的代碼前加鎖,在通路結束後釋放鎖。這樣可以保證同一時刻隻有一個線程可以通路 x,進而避免競态條件問題。

下面是一個簡單的C語言使用互斥鎖保護全局變量的例子:

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 定義互斥鎖

int global_var = 0;

void *thread_func(void *arg) {
    int thread_num = *(int *)arg;
    int i;
    for (i = 0; i < 100000; i++) {
        pthread_mutex_lock(&mutex);  // 加鎖
        global_var++;
        printf("Thread %d: global_var = %d\n", thread_num, global_var);
        pthread_mutex_unlock(&mutex);  // 解鎖
    }
    return NULL;
}

int main() {
    pthread_t thread1, thread2;
    int thread_num1 = 1, thread_num2 = 2;

    // 建立兩個線程
    if (pthread_create(&thread1, NULL, thread_func, &thread_num1) != 0) {
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }
    if (pthread_create(&thread2, NULL, thread_func, &thread_num2) != 0) {
        perror("pthread_create");
        exit(EXIT_FAILURE);
    }

    // 等待兩個線程結束
    if (pthread_join(thread1, NULL) != 0) {
        perror("pthread_join");
        exit(EXIT_FAILURE);
    }
    if (pthread_join(thread2, NULL) != 0) {
        perror("pthread_join");
        exit(EXIT_FAILURE);
    }

    return 0;
}
           

在上面的代碼中,我們定義了一個全局變量 global_var,然後建立了兩個線程 thread1 和 thread2,它們會分别對 global_var 進行加 1 操作。在通路 global_var 的代碼前,我們使用了 pthread_mutex_lock 函數來加鎖,在通路結束後使用 pthread_mutex_unlock 函數來解鎖,以保證同一時刻隻有一個線程可以通路 global_var。

繼續閱讀