亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Linux線程管理必備:解析互斥量與條件變量的詳解

 更新時(shí)間:2013年05月27日 11:43:15   作者:  
本篇文章是對(duì)互斥量與條件變量的應(yīng)用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下

   做過(guò)稍微大一點(diǎn)項(xiàng)目的人都知道,力求程序的穩(wěn)定性和調(diào)度的方便,使用了大量的線程,幾乎每個(gè)模塊都有一個(gè)專門的線程處理函數(shù)。而互斥量與條件變量在線程管理中必不可少,任務(wù)間的調(diào)度幾乎都是由互斥量與條件變量控制。互斥量的實(shí)現(xiàn)與進(jìn)程中的信號(hào)量(無(wú)名信號(hào)量)是類似的,當(dāng)然,信號(hào)量也可以用于線程,區(qū)別在于初始化的時(shí)候,其本質(zhì)都是P/V操作。編譯時(shí),記得加上-lpthread或-lrt哦。

   有關(guān)進(jìn)程間通信(消息隊(duì)列)見(jiàn):進(jìn)程間通信之深入消息隊(duì)列的詳解

一、互斥量

1. 初始化與銷毀:

   對(duì)于靜態(tài)分配的互斥量, 可以初始化為PTHREAD_MUTEX_INITIALIZER等價(jià)于pthread_mutex_init(…, NULL))調(diào)用pthread_mutex_init。

   對(duì)于動(dòng)態(tài)分配的互斥量, 在申請(qǐng)內(nèi)存(malloc)之后,通過(guò)pthread_mutex_init進(jìn)行初始化, 并且在釋放內(nèi)存(free)前需要調(diào)用pthread_mutex_destroy.

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

    int pthread_mutex_destroy(pthread_mutex_t *mutex);

返回值:成功則返回0,出錯(cuò)則返回錯(cuò)誤編號(hào).

說(shuō)明:1、如果使用默認(rèn)的屬性初始化互斥量,只需把a(bǔ)ttr設(shè)為NULL。

           2、銷毀一個(gè)互斥鎖即意味著釋放它所占用的資源,且要求鎖當(dāng)前處于開(kāi)放狀態(tài)。由于在Linux中,互斥鎖并不占用任何資源,因此 LinuxThreads中的pthread_mutex_destroy()除了檢查鎖狀態(tài)以外(鎖定狀態(tài)則返回EBUSY)沒(méi)有其他動(dòng)作。

2. 互斥操作:

   對(duì)共享資源的訪問(wèn), 要對(duì)互斥量進(jìn)行加鎖,如果互斥量已經(jīng)上了鎖, 調(diào)用線程會(huì)阻塞,直到互斥量被解鎖。在完成了對(duì)共享資源的訪問(wèn)后, 要對(duì)互斥量進(jìn)行解鎖。

    int pthread_mutex_lock(pthread_mutex_t *mutex);  //P操作:請(qǐng)求資源(+1)

    int pthread_mutex_trylock(pthread_mutex_t *mutex);

    int pthread_mutex_unlock(pthread_mutex_t *mutex);//V操作:釋放資源(-1)

返回值:成功則返回0,出錯(cuò)則返回錯(cuò)誤編號(hào).

說(shuō)明:1、想給一個(gè)互斥量上鎖,我們調(diào)用pthread_mutex_lock。如果mutex已經(jīng)上鎖,調(diào)用的線程將會(huì)被阻塞,直至信號(hào)量解鎖。

       2、具體說(shuō)一下trylock函數(shù), 這個(gè)函數(shù)是非阻塞調(diào)用模式,也就是說(shuō), 如果互斥量沒(méi)被鎖住,trylock函數(shù)將把互斥量加鎖, 并獲得對(duì)共享資源的訪問(wèn)權(quán)限;如果互斥量被鎖住了,trylock函數(shù)將不會(huì)阻塞等待而直接返回EBUSY, 表示共享資源處于忙狀態(tài)。

       3、要解鎖一個(gè)信號(hào)量,我們調(diào)用phtread_mutex_unlock。

3. 死鎖、同步、與互斥的關(guān)系

3.1 死鎖:

   有時(shí),可能需要同時(shí)訪問(wèn)兩個(gè)資源。您可能正在使用其中的一個(gè)資源,隨后發(fā)現(xiàn)還需要另一個(gè)資源。如果兩個(gè)線程嘗試聲明這兩個(gè)資源,但是以不同的順序鎖定與這些資源相關(guān)聯(lián)的互斥鎖,則會(huì)出現(xiàn)問(wèn)題。例如,如果兩個(gè)線程分別鎖定互斥鎖1 和互斥鎖 2,則每個(gè)線程嘗試鎖定另一個(gè)互斥鎖時(shí),將會(huì)出現(xiàn)死鎖。下面的例子說(shuō)明了可能的死鎖情況。

線程 1

線程 2

pthread_mutex_lock(&m1);

pthread_mutex_lock(&m2);

do something……

pthread_mutex_unlock(&m2);

pthread_mutex_unlock(&m1);

pthread_mutex_lock(&m2);

pthread_mutex_lock(&m1);

do something……

pthread_mutex_unlock(&m1);

pthread_mutex_unlock(&m2);


3.2 同步:  

線程 1

線程 2

pthread_mutex_lock(&m1);

do something……

pthread_mutex_unlock(&m2);

pthread_mutex_lock(&m2);

do something……

pthread_mutex_unlock(&m1);


3.3 互斥: 

線程 1

pthread_mutex_lock(&m1);

do something……//臨界區(qū)(Critical Section)

pthread_mutex_unlock(&m1);


4. 互斥量之前輩總結(jié)

       1.對(duì)共享資源操作前一定要獲得鎖。

       2.完成操作以后一定要釋放鎖。

       3.盡量短時(shí)間地占用鎖。

       4.如果有多鎖, 如獲得順序是ABC連環(huán)扣,釋放順序也應(yīng)該是ABC。

       5.線程錯(cuò)誤返回時(shí)應(yīng)該釋放它所獲得的鎖。

二、條件變量

1. 創(chuàng)建和注銷

    條件變量和互斥鎖一樣,都有靜態(tài)動(dòng)態(tài)兩種創(chuàng)建方式

a. 靜態(tài)方式

    靜態(tài)方式使用PTHREAD_COND_INITIALIZER常量,如: pthread_cond_t  cond = PTHREAD_COND_INITIALIZER

b. 動(dòng)態(tài)方式
   int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)

    使用 cond_attr 指定的屬性初始化條件變量 cond,當(dāng) cond_attr NULL時(shí),使用缺省的屬性。LinuxThreads實(shí)現(xiàn)條件變量不支持屬性,因此 cond_attr參數(shù)實(shí)際被忽略。
c. 
注銷

    int pthread_cond_destroy(pthread_cond_t *cond)

    注銷一個(gè)條件變量需要調(diào)用pthread_cond_destroy(),只有在沒(méi)有線程在該條件變量上等待的時(shí)候才能注銷這個(gè)條件變量,否則返回EBUSY。因?yàn)?/SPAN>Linux實(shí)現(xiàn)的條件變量沒(méi)有分配什么資源,所以注銷動(dòng)作只包括檢查是否有等待線程。

2. 等待和激發(fā)

2.1 等待

   int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
   這個(gè)函數(shù)POSIX線程信號(hào)發(fā)送系統(tǒng)的核心,也是最難以理解的部分,過(guò)程為:解鎖-wait-收到信號(hào)-加鎖-返回。

2.2 設(shè)置時(shí)間的等待

   int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, conststruct timespec *abstime)

    pthread_cond_timedwait pthread_cond_wait一樣,自動(dòng)解鎖互斥量及等待條件變量,但它還限定了等待時(shí)間。如果在 abstime指定的時(shí)間內(nèi) cond未觸發(fā),互斥量 mutex被重新加鎖,并返回錯(cuò)誤 ETIMEDOUTabstime參數(shù)指定一個(gè)絕對(duì)時(shí)間,時(shí)間原點(diǎn)與 time gettimeofday相同:abstime = 0表示 1970 年 1 1 00:00:00 GMT。 

2.3 激發(fā)

    int pthread_cond_signal(pthread_cond_t *cond);
    int pthread_cond_broadcast(pthread_cond_t *cond);

    激發(fā)條件有兩種形式,pthread_cond_signal()激活一個(gè)等待該條件的線程,多個(gè)線程阻塞在此條件變量上時(shí),哪一個(gè)線程被喚醒是由線程的調(diào)度策略所決定的;而pthread_cond_broadcast()激活所有等待線程,這些線程被喚醒后將再次競(jìng)爭(zhēng)相應(yīng)的互斥鎖。

   要注意的是,必須用保護(hù)條件變量的互斥鎖來(lái)保護(hù)激活函數(shù),否則條件滿足信號(hào)有可能在測(cè)試條件和調(diào)用pthread_cond_wait()函數(shù)之間被發(fā)出,從而造成無(wú)限制的等待。 

三、互斥量與條件變量

    互斥量存在的問(wèn)題:從本質(zhì)上說(shuō)互斥量就是一把鎖,互斥量串行執(zhí)行,能確保每次只有一個(gè)線程訪問(wèn)。互斥量是線程程序必需的工具,但它們并非萬(wàn)能的。例如,如果線程正在輪詢等待共享數(shù)據(jù)內(nèi)某個(gè)條件出現(xiàn),那會(huì)發(fā)生什么呢?它可以重復(fù)對(duì)互斥對(duì)象鎖定和解鎖,每次都會(huì)檢查共享數(shù)據(jù)結(jié)構(gòu),以查找某個(gè)值。但這是在浪費(fèi)時(shí)間和資源,而且這種繁忙查詢的效率非常低。同樣,在每次檢查之間讓線程短暫地進(jìn)入睡眠,比如睡眠3s,但是因此線程代碼就無(wú)法最快作出響應(yīng)。

    問(wèn)題的解決: 條件變量通過(guò)允許線程阻塞和等待另一個(gè)線程發(fā)送信號(hào)的方法彌補(bǔ)了互斥鎖的不足,條件變量常和互斥鎖一起使用。使用時(shí),條件變量被用來(lái)阻塞一個(gè)線程,當(dāng)條件不滿足時(shí),線程往往解開(kāi)相應(yīng)的互斥鎖并等待條件發(fā)生變化。一旦其它的某個(gè)線程改變了條件變量,它將通知相應(yīng)的條件變量喚醒一個(gè)或多個(gè)正被此條件變量阻塞的線程。這些線程將重新鎖定互斥鎖并重新測(cè)試條件是否滿足。

四、線程管理相關(guān)代碼

復(fù)制代碼 代碼如下:

//省略了線程互斥量以及條件變量的初始化
//線程管理:阻塞sec秒讀取線程信息
//三個(gè)參數(shù)分別為:線程信息、線程ID、超時(shí)秒數(shù)
bool ManagePthread_TimeReadSignal(PTHREAD_BUF *rbuf, PTHREAD_ID thread_num, int sec)
{
    bool b_valid = false;
    struct timespec to;
    int err;
    to.tv_sec = time(NULL) + sec;
    to.tv_nsec = 0;

 //上鎖
    pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
 //超時(shí)sec秒阻塞等待,類似select
    err = pthread_cond_timedwait(&managePthread.g_pthread_cond[thread_num], &managePthread.g_pthread_mutex[thread_num], &to);
    if(err == ETIMEDOUT)
    {
        pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
        return false;
    }

 //獲取線程信息
    if(managePthread.g_pthread_info[thread_num] == WRITE_FLAG)
    {
        managePthread.g_pthread_info[thread_num] = READ_FLAG;
        memcpy((PTHREAD_BUF *)rbuf, (PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], sizeof(PTHREAD_BUF));
        b_valid = true;
    }

 //解鎖
    pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
    return b_valid;
}
//阻塞讀取線程信息
bool ManagePthread_ReadSignal(PTHREAD_BUF *rbuf, PTHREAD_ID thread_num, bool wait)
{
    bool b_valid = false;
    pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
    if(wait == true)
        pthread_cond_wait(&managePthread.g_pthread_cond[thread_num], &managePthread.g_pthread_mutex[thread_num]);
    if(managePthread.g_pthread_info[thread_num] == WRITE_FLAG)
    {
        managePthread.g_pthread_info[thread_num] = READ_FLAG;
        memcpy((PTHREAD_BUF *)rbuf, (PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], sizeof(PTHREAD_BUF));
        b_valid = true;
    }
    pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
    return b_valid;
}
//激活/發(fā)送線程信息
bool ManagePthread_SendSignal(PTHREAD_BUF *sbuf, PTHREAD_ID thread_num)
{
    bool b_valid = false;
    pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
    managePthread.g_pthread_info[thread_num] = WRITE_FLAG;
    if(sbuf)
    {
        memcpy((PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], (PTHREAD_BUF *)sbuf, sizeof(PTHREAD_BUF));
    }
    pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
    pthread_cond_signal(&managePthread.g_pthread_cond[thread_num]);
    b_valid = true;
    return b_valid;
}
//廣播
bool ManagePthread_BroadcastSignal(PTHREAD_BUF *sbuf, PTHREAD_ID thread_num)
{
    bool b_valid = false;
    pthread_mutex_lock(&managePthread.g_pthread_mutex[thread_num]);
    managePthread.g_pthread_info[thread_num] = WRITE_FLAG;
    memcpy((PTHREAD_BUF *)&managePthread.g_pthread_buf[thread_num], (PTHREAD_BUF *)sbuf, sizeof(PTHREAD_BUF));
    pthread_mutex_unlock(&managePthread.g_pthread_mutex[thread_num]);
    pthread_cond_broadcast(&managePthread.g_pthread_cond[thread_num]);
    b_valid = true;
    return b_valid;
}

相關(guān)文章

  • 關(guān)于《C和指針》的學(xué)習(xí)筆記

    關(guān)于《C和指針》的學(xué)習(xí)筆記

    本篇文章是對(duì)《C和指針》這本書(shū)的學(xué)習(xí)做了筆記介紹。需要的朋友參考下
    2013-05-05
  • C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)與算法之圖的遍歷(二)

    C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)與算法之圖的遍歷(二)

    這篇文章主要是介紹了利用廣度優(yōu)先算法實(shí)現(xiàn)圖的遍歷,文中利用圖文詳細(xì)的介紹了實(shí)現(xiàn)步驟,對(duì)我們學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法有一定的幫助,需要的朋友可以參考一下
    2021-12-12
  • OpenCV 輪廓周圍繪制矩形框和圓形框的方法

    OpenCV 輪廓周圍繪制矩形框和圓形框的方法

    這篇文章主要介紹了OpenCV 輪廓周圍繪制矩形框和圓形框,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • Qt實(shí)現(xiàn)兩個(gè)獨(dú)立窗口的信號(hào)通信

    Qt實(shí)現(xiàn)兩個(gè)獨(dú)立窗口的信號(hào)通信

    這篇文章主要為大家詳細(xì)介紹了Qt實(shí)現(xiàn)兩個(gè)獨(dú)立窗口的信號(hào)通信,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • windows系統(tǒng)下C++調(diào)用matlab程序的方法詳解

    windows系統(tǒng)下C++調(diào)用matlab程序的方法詳解

    這篇文章主要給大家介紹了關(guān)于在windows系統(tǒng)下C++調(diào)用matlab程序的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • C++基于棧的深搜算法實(shí)現(xiàn)馬踏棋盤

    C++基于棧的深搜算法實(shí)現(xiàn)馬踏棋盤

    這篇文章主要為大家詳細(xì)介紹了C++基于棧的深搜算法實(shí)現(xiàn)馬踏棋盤,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易版掃雷小游戲

    C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易版掃雷小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易版掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • 排列和組合算法的實(shí)現(xiàn)方法_C語(yǔ)言經(jīng)典案例

    排列和組合算法的實(shí)現(xiàn)方法_C語(yǔ)言經(jīng)典案例

    下面小編就為大家?guī)?lái)一篇排列和組合算法的實(shí)現(xiàn)方法_C語(yǔ)言經(jīng)典案例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09
  • C++ 位圖及位圖的實(shí)現(xiàn)原理

    C++ 位圖及位圖的實(shí)現(xiàn)原理

    位圖實(shí)際上就是一個(gè)數(shù)組,因?yàn)閿?shù)組有隨機(jī)訪問(wèn)的功能,比較方便查找,這個(gè)數(shù)組一般是整形,今天通過(guò)本文給大家分享c++位圖的實(shí)現(xiàn)原理及實(shí)現(xiàn)代碼,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • 由static_cast和dynamic_cast到C++對(duì)象占用內(nèi)存的全面分析

    由static_cast和dynamic_cast到C++對(duì)象占用內(nèi)存的全面分析

    下面小編就為大家?guī)?lái)一篇由static_cast和dynamic_cast到C++對(duì)象占用內(nèi)存的全面分析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01

最新評(píng)論