執行緒同步與互斥:互斥鎖

千鋒教育官方發表於2019-09-23


為什麼需要互斥鎖?

 

在多工作業系統中,同時執行的多個任務可能都需要使用同一種資源。這個過程有點類似於,公司部門裡,我在使用著印表機列印東西的同時(還沒有列印完),別人剛好也在此刻使用印表機列印東西,如果不做任何處理的話,列印出來的東西肯定是錯亂的。

 

下面我們用程式模擬一下這個過程,執行緒一需要列印“ hello ”,執行緒二需要列印“ world ”,不加任何處理的話,列印出來的內容會錯亂:

 

#include <stdio.h>  

#include <pthread.h>  

#include <unistd.h>  

  

// 印表機  

void printer(char *str)  

{  

    while(*str!='\0')  

    {  

        putchar(*str);    

        fflush(stdout);  

        str++;  

        sleep(1);  

    }  

    printf("\n");   

}  

  

// 執行緒一  

void *thread_fun_1(void *arg)  

{  

    char *str = "hello";  

    printer(str); //列印  

}  

  

// 執行緒二  

void *thread_fun_2(void *arg)  

{  

    char *str = "world";  

    printer(str); //列印  

}  

  

int main(void)  

{  

    pthread_t tid1, tid2;  

      

    // 建立 2 個執行緒  

    pthread_create(&tid1, NULL, thread_fun_1, NULL);  

    pthread_create(&tid2, NULL, thread_fun_2, NULL);  

  

    // 等待執行緒結束,回收其資源  

    pthread_join(tid1, NULL);  

    pthread_join(tid2, NULL);   

      

    return 0;  

}  

 

執行結果如下:

 

實際上,印表機是有做處理的,我在列印著的時候別人是不允許列印的,只有等我列印結束後別人才允許列印。這個過程有點類似於,把印表機放在一個房間裡,給這個房間安把鎖,這個鎖預設是開啟的。當 A 需要列印時,他先過來檢查這把鎖有沒有鎖著,沒有的話就進去,同時上鎖在房間裡列印。而在這時,剛好 B 也需要列印,B 同樣先檢查鎖,發現鎖是鎖住的,他就在門外等著。而當 A 列印結束後,他會開鎖出來,這時候 B 才進去上鎖列印。

 

而線上程裡也有這麼一把鎖——互斥鎖(mutex),互斥鎖是一種簡單的加鎖的方法來控制對共享資源的訪問,互斥鎖只有兩種狀態,即上鎖( lock )和解鎖( unlock )。

 

 

 

互斥鎖的操作流程如下:

 

1)在訪問共享資源後臨界區域前,對互斥鎖進行加鎖。

2)在訪問完成後釋放互斥鎖導上的鎖。

3)對互斥鎖進行加鎖後,任何其他試圖再次對互斥鎖加鎖的執行緒將會被阻塞,直到鎖被釋放。

 

 

互斥鎖的資料型別是:  pthread_mutex_t  

互斥鎖基本操作

 

以下函式需要的標頭檔案:

#include <pthread.h>

 

1)初始化互斥鎖

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

 

功能:

初始化一個互斥鎖。

引數:

mutex:互斥鎖地址。型別是 pthread_mutex_t 。

attr:設定互斥量的屬性,通常可採用預設屬性,即可將 attr 設為 NULL。

 

可以使用宏 PTHREAD_MUTEX_INITIALIZER 靜態初始化互斥鎖,比如:

pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER;

這種方法等價於使用 NULL 指定的 attr 引數呼叫 pthread_mutex_init() 來完成動態初始化,不同之處在於 PTHREAD_MUTEX_INITIALIZER 宏不進行錯誤檢查。

返回值:

成功:0,成功申請的鎖預設是開啟的。

失敗:非 0 錯誤碼

 

2)上鎖

 

int pthread_mutex_lock(pthread_mutex_t *mutex);

 

功能:

對互斥鎖上鎖,若互斥鎖已經上鎖,則呼叫者一直阻塞,直到互斥鎖解鎖後再上鎖。

引數:

mutex:互斥鎖地址。

返回值:

成功:0

 

失敗:非 0 錯誤碼

int pthread_mutex_trylock(pthread_mutex_t *mutex);

呼叫該函式時,若互斥鎖未加鎖,則上鎖,返回 0;若互斥鎖已加鎖,則函式直接返回失敗,即 EBUSY。

 

3)解鎖

 

int pthread_mutex_unlock(pthread_mutex_t * mutex);

 

功能:

對指定的互斥鎖解鎖。

引數:

mutex:互斥鎖地址。

返回值:

成功:0

失敗:非 0 錯誤碼

 

4)銷燬互斥鎖

 

int pthread_mutex_destroy(pthread_mutex_t *mutex);

功能:

銷燬指定的一個互斥鎖。互斥鎖在使用完畢後,必須要對互斥鎖進行銷燬,以釋放資源。

引數:

mutex:互斥鎖地址。

返回值:

成功:0

失敗:非 0 錯誤碼

 

互斥鎖應用例項

我們透過互斥鎖完善上面的例子,示例程式碼如下:

#include <stdio.h>  

#include <pthread.h>  

#include <unistd.h>  

  

pthread_mutex_t mutex; //互斥鎖  

  

// 印表機  

void printer(char *str)  

{  

    pthread_mutex_lock(&mutex); //上鎖  

    while(*str!='\0')  

    {  

        putchar(*str);    

        fflush(stdout);  

        str++;  

        sleep(1);  

    }  

    printf("\n");   

    pthread_mutex_unlock(&mutex); //解鎖  

}    

// 執行緒一  

void *thread_fun_1(void *arg)  

{  

    char *str = "hello";  

    printer(str); //列印  

}  

// 執行緒二  

void *thread_fun_2(void *arg)  

{  

    char *str = "world";  

    printer(str); //列印  

}  

  

int main(void)  

{  

    pthread_t tid1, tid2;  

    pthread_mutex_init(&mutex, NULL); //初始化互斥鎖    

    // 建立 2 個執行緒  

    pthread_create(&tid1, NULL, thread_fun_1, NULL);  

    pthread_create(&tid2, NULL, thread_fun_2, NULL);  

  

    // 等待執行緒結束,回收其資源  

    pthread_join(tid1, NULL);  

    pthread_join(tid2, NULL);   

    pthread_mutex_destroy(&mutex); //銷燬互斥鎖   

    return 0;  

}  

 

執行結果如下:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69914734/viewspace-2657988/,如需轉載,請註明出處,否則將追究法律責任。

相關文章