1. 程式人生 > >Linux C 程式設計——互斥鎖mutex

Linux C 程式設計——互斥鎖mutex

1、多執行緒的問題引入

多執行緒的最大的特點是資源的共享,但是,當多個執行緒同時去操作(同時去改變)一個臨界資源時,會破壞臨界資源。如利用多執行緒同時寫一個檔案:

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

const char filename[] = "hello";

void* thread(void *id){

        int num = *(int *)id;

        // 寫檔案的操作
        FILE *fp = fopen(filename, "a+"
); int start = *((int *)id); int end = start + 1; setbuf(fp, NULL);// 設定緩衝區的大小 fprintf(stdout, "%d\n", start); for (int i = (start * 10); i < (end * 10); i ++){ fprintf(fp, "%d\t", i); } fprintf(fp, "\n"); fclose(fp); return
NULL; } int main(){ int num_thread = 5; pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread); int * id = (int *)malloc(sizeof(int) * num_thread); for (int i = 0; i < num_thread; i++){ id[i] = i; if (pthread_create(&pt[i], NULL
, thread, &id[i]) != 0){ printf("thread create failed!\n"); return 1; } } for (int i = 0; i < num_thread; i++){ pthread_join(pt[i], NULL); } // 釋放資源 free(pt); free(id); return 0; }

執行以上的程式碼,我們會發現,得到的結果是混亂的,出現上述的最主要的原因是,我們在編寫多執行緒程式碼的過程中,每一個執行緒都嘗試去寫同一個檔案,這樣便出現了上述的問題,這便是共享資源的同步問題,在Linux程式設計中,執行緒同步的處理方法包括:訊號量,互斥鎖和條件變數。

2、互斥鎖

互斥鎖是通過鎖的機制來實現執行緒間的同步問題。互斥鎖的基本流程為:

  • 初始化一個互斥鎖:pthread_mutex_init()函式
  • 加鎖:pthread_mutex_lock()函式或者pthread_mutex_trylock()函式
  • 對共享資源的操作
  • 解鎖:pthread_mutex_unlock()函式
  • 登出互斥鎖:pthread_mutex_destory()函式

其中,在加鎖過程中,pthread_mutex_lock()函式和pthread_mutex_trylock()函式的過程略有不同:

  • 當使用pthread_mutex_lock()函式進行加鎖時,若此時已經被鎖,則嘗試加鎖的執行緒會被阻塞,直到互斥鎖被其他執行緒釋放,當pthread_mutex_lock()函式有返回值時,說明加鎖成功;
  • 而使用pthread_mutex_trylock()函式進行加鎖時,若此時已經被鎖,則會返回EBUSY的錯誤碼。

同時,解鎖的過程中,也需要滿足兩個條件:

  • 解鎖前,互斥鎖必須處於鎖定狀態;
  • 必須由加鎖的執行緒進行解鎖。

當互斥鎖使用完成後,必須進行清除。

有了以上的準備,我們重新實現上述的多執行緒寫操作,其實現程式碼如下所示:

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

pthread_mutex_t mutex;

const char filename[] = "hello";

void* thread(void *id){

        int num = *(int *)id;
        // 加鎖

        if (pthread_mutex_lock(&mutex) != 0){
                fprintf(stdout, "lock error!\n");
        }
        // 寫檔案的操作
        FILE *fp = fopen(filename, "a+");
        int start = *((int *)id);
        int end = start + 1;
        setbuf(fp, NULL);// 設定緩衝區的大小
        fprintf(stdout, "%d\n", start);
        for (int i = (start * 10); i < (end * 10); i ++){
                fprintf(fp, "%d\t", i);
        }
        fprintf(fp, "\n");
        fclose(fp);

        // 解鎖
        pthread_mutex_unlock(&mutex);

        return NULL;
}

int main(){
        int num_thread = 5;
        pthread_t *pt = (pthread_t *)malloc(sizeof(pthread_t) * num_thread);
        int * id = (int *)malloc(sizeof(int) * num_thread);

        // 初始化互斥鎖
        if (pthread_mutex_init(&mutex, NULL) != 0){
                // 互斥鎖初始化失敗
                free(pt);
                free(id);
                return 1;
        }

        for (int i = 0; i < num_thread; i++){
                id[i] = i;
                if (pthread_create(&pt[i], NULL, thread, &id[i]) != 0){
                        printf("thread create failed!\n");
                        return 1;
                }
        }
        for (int i = 0; i < num_thread; i++){
                pthread_join(pt[i], NULL);
        }
        pthread_mutex_destroy(&mutex);

        // 釋放資源
        free(pt);
        free(id);
        return 0;
}

最終的結果為:

這裡寫圖片描述