線程同步與互斥(死鎖的避免)

臨界資源:

樂山網站制作公司哪家好,找成都創(chuàng)新互聯!從網頁設計、網站建設、微信開發(fā)、APP開發(fā)、成都響應式網站建設等網站項目制作,到程序開發(fā),運營維護。成都創(chuàng)新互聯自2013年創(chuàng)立以來到現在10年的時間,我們擁有了豐富的建站經驗和運維經驗,來保證我們的工作的順利進行。專注于網站建設就選成都創(chuàng)新互聯

一個進程的資源對于運行在它內部的線程是共享的,一次只允許一個線程使用的資源叫做臨界資源

臨界區(qū):

訪問臨界資源的那段程序叫做臨界區(qū)

線程的同步:

同步就是協同步調,按照預定的先后順序執(zhí)行。

“同”字應是指協同、協助、互相配合。

線程的互斥:

某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性。

但互斥無法限制訪問者對資源的訪問順序,即訪問是無序的。

互斥量(mutex)

多個線程同時訪問共享數據時,經常會發(fā)生沖突,因此常常引入互斥鎖來解決這個問題。

沖突:例如對一個全局變量g_var進行加一操作,這樣的操作需要三條指令來完成:(1、把該變量的值從內存讀到寄存器;2、寄存器進行加一操作;3、把修改后的值寫回內存),因為這三條指令的執(zhí)行不是原子操作,有可能線程1執(zhí)行了第一步(把變量值讀到寄存器),此時內核調度線程2,線程2也把該值讀到寄存器,它們都進行加一操作后寫回內存,導致最后結果只加了一次,而我們希望是兩次。

解決:引入互斥鎖,獲得鎖的線程可以對變量進行“讀-修改-寫”操作,這個操作是原子的,完成這個操作后釋放鎖給別的線程,沒有獲得鎖的線程只能等待而不能訪問該共享數據。

有關函數:

1.互斥鎖的初始化及銷毀

其中初始化既可以使用函數pthread_mutex_init(),也可以定義pthread_mutex_t類型的變量mutex,并賦值PTHREAD_MUTEX_INITIALIZER

線程同步與互斥(死鎖的避免)

線程同步與互斥(死鎖的避免)

2.對mutex的加鎖及解鎖

一個線程可以調用pthread_mutex_lock獲得Mutex,如果這時另一個線程已經調用pthread_mutex_lock獲得了該Mutex,則當前線程需要掛起等待,直到另一個線程調用pthread_mutex_unlock釋放Mutex,當前線程被喚醒,才能獲得該Mutex并繼續(xù)執(zhí)行。

如果一個線程既想獲得鎖,又不想掛起等待,可以調用pthread_mutex_trylock,如果Mutex已經被另一個線程獲得,這個函數會失敗返回EBUSY,而不會使線程掛起等待。

線程同步與互斥(死鎖的避免)

線程同步與互斥(死鎖的避免)


Mutex的lock和unlock的偽碼(以x86的xchg指令為例):

線程同步與互斥(死鎖的避免)

不使用互斥量代碼:

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

void *thread(void *arg)
{
    int count=2000;
    while(count-- >0){
        int var=g_var;
        printf("this is thread%d,g_var=%d\n",(int)arg,g_var);
        g_var=var+1;
    }
}

int main()
{
    pthread_t tid1,tid2;
    
    if(pthread_create(&tid1,NULL,thread,(void*)1)!=0){
        printf("creat tid1 is failed\n");
    }
    if(pthread_create(&tid1,NULL,thread,(void*)2)!=0){
        printf("creat tid1 is failed\n");
    }
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);
    
    return 0;
}

運行結果:

第一次運行線程1和線程2一共加了2275次

線程同步與互斥(死鎖的避免)

第二次運行一共把g_var加了2000次

線程同步與互斥(死鎖的避免)

使用互斥量實現代碼:

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

//pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;

struct info
{
    int _var;
    pthread_mutex_t  *_mutex_lock;
}info;

int g_var=0;
void *thread(void *arg)
{
    struct info* _lock=(struct info*)arg;
    int count=2000;
    while(count-- >0){
        pthread_mutex_lock(_lock->_mutex_lock);
        int var=g_var;
        printf("this is thread%d,g_var=%d\n",_lock->_var,g_var);
        g_var=var+1;
        pthread_mutex_unlock(_lock->_mutex_lock);
    }   
}

int main()
{
    pthread_t tid1,tid2;
    pthread_mutex_t mutex_lock;
    int err=pthread_mutex_init(&mutex_lock,NULL);
    if(err!=0){
        printf("%s\n",strerror(err));
    }

    struct info info1;
    info1._var=1;
    info1._mutex_lock=&mutex_lock;

    if(pthread_create(&tid1,NULL,thread,&info1)!=0){
        printf("creat tid1 is failed\n");
    }

    struct info info2;
    info2._var=2;
    info2._mutex_lock=&mutex_lock;

    if(pthread_create(&tid2,NULL,thread,&info2)!=0){
        printf("creat tid2 is failed\n");
    }
    
    pthread_join(tid1,NULL);
    pthread_join(tid2,NULL);

    err=pthread_mutex_destroy(&mutex_lock);
    if(err!=0){
        printf("%s\n",strerror(err));
    }

    return 0;
}

運行結果:

線程1和線程2共執(zhí)行了4000次

線程同步與互斥(死鎖的避免)

總結:當一個線程已經獲得鎖,另一個線程需掛起等待,當該線程釋放鎖后,會喚醒正在等待線程。每個mutex都有一個等待隊列,當線程掛起時,就加入該等待隊列,狀態(tài)設置為睡眠。一個線程要喚醒別的線程,只需要從等待隊列中取出一項加入就緒隊列并把它的狀態(tài)設置為就緒。

有的時候一個線程會兩次獲得鎖,第一次正常獲得,第二次獲得所得時候發(fā)現鎖已經被別占用,它就會掛起,導致自己占用了鎖卻處于掛起狀態(tài),這樣就產生了死鎖。

死鎖:

產生死鎖的原因

1、進程資源不足

2、進程推進的順序不合適

3、系統資源的分配不當

產生死鎖的必要條件:

1、互斥條件:一個資源一次只能被一個進程使用

2、請求與保持條件:一個已經進程因請求資源而阻塞,對已獲得的資源保持不放

3、不剝奪條件:進程已獲得的資源,在沒使用完之前,不能強行剝奪

4、循環(huán)等待條件:若干個進程之間形成一種頭尾相接的循環(huán)等待資源關系

產生死鎖時,以上四個必要條件一定都成立。



網頁名稱:線程同步與互斥(死鎖的避免)
瀏覽路徑:http://muchs.cn/article8/ijdgop.html

成都網站建設公司_創(chuàng)新互聯,為您提供虛擬主機、App設計搜索引擎優(yōu)化、網頁設計公司、關鍵詞優(yōu)化、營銷型網站建設

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯

商城網站建設