Linux C 程式設計——互斥鎖mutex
阿新 • • 發佈:2019-02-17
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;
}
最終的結果為: