本文將會給出互斥量的詳細解說,并用一個互斥量解決上一篇文章中,要使用兩個信號量才能解決的只有子線程結束了對輸入的處理和統(tǒng)計后,主線程才能繼續(xù)執(zhí)行的問題。
一、什么是互斥量
互斥量是另一種用于多線程中的同步訪問方法,它允許程序鎖住某個對象,使得每次只能有一個線程訪問它。為了控制對關鍵代碼的訪問,必須在進入這段代碼之前鎖住一個互斥量,然后在完成操作之后解鎖。
二、互斥量的函數(shù)的使用
它們的定義與使用信號量的函數(shù)非常相似,它們的定義如下:
#include <pthread.h> int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr); int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_destroy(pthread_mutex_t *mutex);
它們的意義就如它們的名字所示的那樣,成功時返回0,失敗時返回錯誤代碼,它們并不設置errno。
pthread_mutex_init函數(shù)中的參數(shù)mutexattr指定互斥量的屬性,在這里我們并不關心互斥量的屬性,所以把它設置為NULL,使用默認屬性即可。同樣的,pthread_mutex_lock和pthread_mutex_unlock都是原子操作,如果一個線程調用pthread_mutex_lock試圖鎖住互斥量,而該互斥量,又被其他線程鎖住(占用),則該線程的pthread_mutex_lock調用就會阻塞,直到其他線程對該互斥量進行解鎖,該線程才能獲得該互斥量,pthread_mutex_lock調用才會返回。
注意,使用互斥量的默認屬性,如果程序試圖對一個已經加鎖的互斥量調用pthread_mutex_lock,程序就會阻塞,而又因為擁有互斥量的這個線程正是現(xiàn)在被阻塞的線程,所以這個互斥量就永遠不會被解鎖,也就是說,程序就會進入死鎖的狀態(tài)。在使用時要多加注意,確保在同一個線程中,對加鎖的互斥再次進行加鎖前要對其進行解鎖。
三、使用互斥量進行線程同步
下面以一個簡單的多線程程序來演示如何使用互斥量來進行線程同步。在主線程中,我們創(chuàng)建子線程,并把數(shù)組msg作為參數(shù)傳遞給子線程,然后主線程調用函數(shù)pthread_mutex_lock對互斥量加鎖,等待輸入,輸入完成后,調用函數(shù)pthread_mutex_unlock對互斥量解鎖,從而使線程函數(shù)中的對互斥量加鎖的pthread_mutex_lock函數(shù)返回并執(zhí)行子線程中的代碼。線程函數(shù)在把字符串的小寫字母變成大寫并統(tǒng)計輸入的字符數(shù)量之后,它調用pthread_mutex_unlock對互斥量解鎖,使主線程能夠繼續(xù)獲得互斥量(即對其加鎖函數(shù)返回),再次執(zhí)行輸入功能直到主線程再次調用pthread_mutex_unlock對其解鎖,一直如此重復,直到輸入end。
源文件為lockthread.c,源代碼如下:
、#include <unistd.h> #include <pthread.h> #include <stdlib.h> #include <stdio.h> #include <string.h> //聲明線程函數(shù)和互斥量 void* thread_func(void *msg); pthread_mutex_t mutex; #define MSG_SIZE 512 int main() { int res = -1; pthread_t thread; void *thread_result = NULL; char msg[MSG_SIZE] = {'/0'}; //初始化互斥量,使用默認的互斥量屬性 res = pthread_mutex_init(&mutex, NULL); if(res != 0) { perror("pthread_mutex_init failed/n"); exit(EXIT_FAILURE); } //創(chuàng)建子線程,并把msg作為線程函數(shù)的參數(shù)傳遞給thread_func res = pthread_create(&thread, NULL, thread_func, msg); if(res != 0) { perror("pthread_create failed/n"); exit(EXIT_FAILURE); } //輸入字符串,以串‘end'結束 printf("Input some test. Enter 'end' to finish/n"); //把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據 pthread_mutex_lock(&mutex); while(strcmp("end/n", msg) != 0) { if(strncmp("TEST", msg, 4) == 0) { strcpy(msg, "copy_data/n"); } else { fgets(msg, MSG_SIZE, stdin); } //把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據 pthread_mutex_unlock(&mutex); sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機會 pthread_mutex_lock(&mutex); } pthread_mutex_unlock(&mutex); printf("/nWaiting for thread finish.../n"); //等待子線程結束 res = pthread_join(thread, &thread_result); if(res != 0) { perror("pthread_join failed/n"); exit(EXIT_FAILURE); } printf("Thread joined/n"); //清理互斥量 pthread_mutex_destroy(&mutex); exit(EXIT_SUCCESS); } void* thread_func(void *msg) { int i = 0; char *ptr = msg; sleep(1); //把互斥量mutex加鎖,以確保同一時間只有該線程可以訪問msg中的數(shù)據 pthread_mutex_lock(&mutex); while(strcmp("end/n", msg) != 0) { //把小寫字母變成大寫 for(i = 0; ptr[i] != '/0'; ++i) { if(ptr[i] >= 'a' && ptr[i] <='z') { ptr[i] -= 'a' - 'A'; } } printf("You input %d characters/n", i-1); printf("To uppercase: %s/n", ptr); //把互斥量mutex解鎖,讓其他的線程可以訪問msg中的數(shù)據 pthread_mutex_unlock(&mutex); sleep(1);//休眠1秒再繼續(xù)循環(huán),讓其他線程有執(zhí)行的機會 pthread_mutex_lock(&mutex); } pthread_mutex_unlock(&mutex); //退出線程 pthread_exit(NULL); }
新聞熱點
疑難解答