互斥鎖&屬性

本篇我記錄一下自己學習互斥鎖的成果。

線程同步的概述:

    當線程A在對一個共享資源執行寫操作時,如果此時線程B恰好也對這個共享資源執行寫操作,那麼在進程中就會出現兩個線程同時對這個共享資源進行寫操作,會出現什麼結果呢?當然是會破壞我們寫入的數據,造成不可預計的錯誤。

    而使用互斥鎖(mutex)就正好可以解決這一問題,當線程A在操作(讀/寫)共享資源時,對其進行加鎖,此時如果線程B也要對這個共享資源進行操作時,由於這個鎖的存在會線程B被阻塞,直到線程A釋放掉它之前加在這個共享資源上的鎖時,線程B纔會變成可運行狀態。

我使用僞代碼來表示:

lock(&mutex);

訪問共享資源

unlock(&mutex);

其本質並不是把數據“鎖住”,而是爲線程提供一種串行化執行的機制(讓不同的線程避免在同一時間去操作數據),我曾做過一個驗證,fun1和fun2是供不同線程執行的程序,如果我註銷掉fun2的鎖,並且在fun1鎖住後不釋放,那麼在線程調用fun2的時候它依舊會操作到數據。

正常情況下,如果fun1和fun2遵循我們的互斥鎖約定,當其中任何一個線程獲得互斥鎖後,其他試圖獲得這個鎖的線程都會被阻塞,這樣就巧妙的將兩個線程分別安排在不同的時段執行,保證了任何時刻下只有唯一的線程有“權利”去操作這個共享資源。(我一開始也是誤解了互斥鎖的真正含義,後來經過多次實例驗證才知道這點)

代碼如下:

int num = 3;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

pthread_t TID1, TID2;

/*線程調用函數*/

void *fun1(void *arg)

{

    int ret;

    ret =pthread_mutex_lock(&lock);

    if (0 != ret)

    {

       printf("pthreada lock error\n");

       return ((void *)-1);

    }

    num = num + 1;

    printf("in thepthread A num is %d\n", num);

    while(1);

    //pthread_mutex_unlock(&lock);

    return ((void *)-1);

}  

/*線程調用函數*/

void *fun2(void *arg)

{

    int ret;

    //ret =pthread_mutex_lock(&lock);

    if (0 != ret)

    {

       printf("pthreadb lock error\n");

       return ((void *)-1);

    }

    int num = 77;

    printf("in thepthread B num is %d\n", num);

    //pthread_mutex_unlock(&lock);

    return ((void *)-1);

}

互斥鎖的初始化:

互斥鎖是使用 pthread_mutex_t數據類型來表示的。

在使用互斥鎖之前要對其進行初始化。

  • 靜態分配

Eg.

Pthread_mutex_tlock = PTHREAD_MUTEX_INITIALIZER

  • 動態分配

Eg.

Structfoo

{

intf_count;

pthread_mutex_tf_lock’

intfid;

}

Structfoo *fp;

Fp= malloc(sizeof(struct foo));

Pthread_mutex_init(&fp->f_lock,&NULL); 

Pthread_mutex_destory(&fp->f_lock);

Free(fp);

 

上面可以看到,

在動態初始化的時候,用到了如下兩個函數:

  • 互斥鎖初始化:

在動態初始化之前要申請好內存

intpthread_mutex_init(pthread_mutex_t *restrict mutex,

                       constpthread_mutexattr_t *restrict attr);

  • 銷燬互斥鎖

在銷燬之前要釋放動態申請的內存

intpthread_mutex_destory(pthread_mutex_t *mutex);

互斥鎖的加鎖&解鎖:

  • 對互斥鎖進行加鎖

int pthread_mutex_lock(pthread_mutex_t*mutex);

返回值:若成功,返回0;否則返回錯誤編號

線程A調用該函數加鎖以後,如果線程B再調用這個函數對線程A加過鎖的互斥鎖進行加鎖,線程B將被阻塞直到線程A釋放這個鎖。

  • 嘗試對互斥鎖進行加鎖

intpthread_mutex_trylock(pthread_mutex_t *mutex);

返回值:若成功,返回0;否則返回錯誤編號

如果調用該函數時,互斥鎖處於未解鎖狀態,那麼pthread_mutex_trylock將會鎖住互斥鎖,不會出現阻塞,直接返回0,否則就會失敗,並返回EBUSY

  • 對互斥鎖進行解鎖

intpthread_mutex_unlock(pthread_mutex_t *mutex);

返回值:若成功,返回0;否則返回錯誤編號

避免死鎖:

  • 如果線程試圖對同一個互斥鎖加鎖兩次,那麼他就會陷入死鎖狀態;
  • 線程A一直佔着 互斥鎖1 ,這時它試圖對互斥鎖2 進行加鎖,

線程B此時佔着 互斥鎖2,此時它也試圖對 互斥鎖1 進行加鎖;

這種情況下就出現了死鎖的場景。

避免這種死鎖的方式:

1.  線程B可以先釋放自己目前佔有的鎖,過一段時間再去嘗試加鎖;

2.  讓兩個線程以相同的順序加鎖,這樣可以避免死鎖

互斥鎖的屬性:

互斥鎖屬性是用pthread_mutexattr_t結構表示的,對於非默認屬性可以使用如下倆個函數來初始化和反初始化:

intpthread_mutexattr_init(pthread_mutexattr_t *attr);

lint pthread_mutexattr_destroy(pthread_mutexattr_t*attr);

兩個函數的返回值:若成功,返回0;若失敗,返回錯誤編號

共享屬性:

該屬性有兩種情況:

  • PTHREAD_PROCESS_PRIVATE 這種是默認情況,表示互斥鎖只能在本進程中使用
  • PTHREAD_PROCESS_SHARED  表示互斥鎖可以在不同進程間使用

使用如下兩個函數來設置:

1.  int pthread_mutexattr_getpshared(constpthread_mutexattr_t *restrict attr,int *restrict pshared);

2.  intpthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);

返回值:若成功,返回0;若失敗,返回錯誤編碼



發佈了25 篇原創文章 · 獲贊 6 · 訪問量 5952
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章