條件變量與信號(hào)量

條件變量

條件變量的引入是為了解決互斥鎖中的循環(huán)等待問題,其希望引入一種掛起综膀、喚醒的機(jī)制來實(shí)現(xiàn)cpu的高效利用
使用條件變量解決生產(chǎn)者消費(fèi)者問題:

int empty_slot = 5;
int filled_slot = 0;
struct cond empty_cond;//緩沖區(qū)無空位(滿)
struct lock empty_cnt_lock;//互斥鎖
struct cond filled_cond;//緩沖區(qū)無數(shù)據(jù)(空)
struct lock filled_cnt_lock;//互斥鎖

void producer(void)
{
    int new_msg;
    while(TRUE){
        new_msg = prodece_new();
        lock(&empty_cnt_lock);//加鎖澳迫,進(jìn)入臨界區(qū)
        while(empty_slot == 0)//緩沖區(qū)無空槽
            //掛起當(dāng)前線程,并釋放互斥鎖(原子性)剧劝,其中兩個(gè)形參分別為條件變量和互斥鎖
            cond_wait(&empty_cond,&empty_cnt_lock);//等待slot>0橄登,故empty_cond
        empty_slot--;
        unlock(&empty_cnt_lock);
        
        buffer_add_safe(new_msg);//利用互斥鎖來生產(chǎn)
        
        lock(&filled_cnt_lock);
        filled_slot++;
        cond_signal(&filled_cond);//一般放在臨界區(qū)內(nèi)喚醒
        unlock(&filled_cnt_lock);
    }
}
void consumer(void)
{
    int cur_msg;
    while(TRUE){
        lock(&filled_cnt_lock);//加鎖,進(jìn)入臨界區(qū)
        while(filled_slot == 0)//緩沖區(qū)無數(shù)據(jù)
            //掛起當(dāng)前線程讥此,并釋放互斥鎖(原子性)拢锹,其中兩個(gè)形參分別為條件變量和互斥鎖
            cond_wait(&filled_cond,&filled_cnt_lock);
        filled_slot--;
        unlock(&filled_cnt_lock);
        
        cur_msg = buffer_remove_safe();
        
        lock(&empty_cnt_lock);
        empty_slot++;
        cond_signal(&empty_cond);//喚醒等待在此變量上的生產(chǎn)者
        unlock(&empty_cnt_lock);
        consume_msg(cur_msg);
    }
}

條件變量的實(shí)現(xiàn)中要注意,當(dāng)線程調(diào)用cond_wait()時(shí)需要將當(dāng)前線程加入等待隊(duì)列并原子地掛起當(dāng)前線程并釋放鎖

void cond_wait(條件變量萄喳,互斥鎖){
      加入條件變量的等待隊(duì)列
      原子掛起并放互斥鎖
      重新獲得鎖
}

信號(hào)量semaphore [?sem?f??r]

Dijkstra提出了信號(hào)量機(jī)制卒稳,并只可以通過P(Proberen 檢驗(yàn)) V(Verhogen 自增)操作來進(jìn)行更新信號(hào)量,一般分別用wait和singal表示他巨。wait檢查信號(hào)量的值充坑,小于等于0就循環(huán)等待,大于0就消耗資源染突,即減少信號(hào)量的值捻爷。signal會(huì)增加信號(hào)量的值供wait使用。
信號(hào)量解決生產(chǎn)者消費(fèi)者問題:

sem_t empty_slot;//空閑的緩沖區(qū)資源
sem_t filled_slot;//已經(jīng)填入的資源

void producer(){
    int new_msg;
    while(TRUE){
        new_msg = produce_new();
        wait(&empty_slot);//P操作
        buffer_add_safe(new_msg);//利用互斥鎖進(jìn)行安全增加信息
        signal(&filled_slot);//V操作
    }
}
void consumer(){
    int cur_msg;
    while(TRUE){
        wait(&filled_slot);//P操作
        cur_msg = buffer_remove_safe();//利用互斥鎖進(jìn)行安全消耗信息
        signal(&empty_slot);//V操作
        consume(cur_msg);
    }
}

信號(hào)量實(shí)現(xiàn)時(shí)存在一些問題:當(dāng)多個(gè)線程共享信號(hào)量時(shí)份企,如果不進(jìn)行原子更新信號(hào)量就會(huì)出現(xiàn)某個(gè)線程更新了舊值也榄,類似于CPU cache對(duì)不同線程的不可見問題。其次司志,就算原子更新甜紫,如果出現(xiàn)多個(gè)線程同時(shí)對(duì)信號(hào)量進(jìn)行減少操作降宅,會(huì)出現(xiàn)負(fù)值。
為了解決以上的問題囚霸,我們需要利用互斥鎖和條件變量來實(shí)現(xiàn)信號(hào)量

struct sem{
    int value;//沒有線程等待時(shí)钉鸯,value>=0,為剩余資源數(shù);有線程等待則為等待的線程數(shù)
    int wakeup;//有線程等待時(shí)可用資源數(shù)
    struct lock sem_lock;
    struct cond sem_cond;
}

void wait(struct sem *S){
    lock(&S->sem_lock);
    S->value--;
    if(S->value < 0){
        do{
            cond_wait(&S->sem_cond, &S->sem_lock);
        }while(S->wakeup == 0);
        S->wakeup--;
    }
    unlock(&S->sem_lock);
}

void signal(struct sem *S){
    lock(&S->sem_lock);
    S->value++;
    if(S->value <= 0){
        S->wakeup++;
        cond_signal(&S->sem_cond);
    }
    unlock(&S-sem_lock);
}

進(jìn)入wait后首先將value-1邮辽,如果值>=0唠雕,則代表還有空閑資源,直接unlock吨述,如果小于0就查看wakeup岩睁,如果wakeup為0,就掛起線程揣云。

互斥鎖與信號(hào)量的異同

當(dāng)信號(hào)量的初值為1捕儒,且在0和1之間變化時(shí),成為二元信號(hào)量邓夕。其與互斥鎖的區(qū)別在于:互斥鎖有擁有者這一概念刘莹,信號(hào)量則沒有》俑眨互斥鎖由同一線程加放鎖点弯,信號(hào)量可以由不同線程進(jìn)行PV操作。
計(jì)數(shù)信號(hào)量允許多個(gè)線程矿咕,且值為剩余可用資源數(shù)量抢肛。互斥鎖保證多個(gè)線程對(duì)一個(gè)共享資源的互斥訪問碳柱,信號(hào)量用于協(xié)調(diào)多個(gè)線程對(duì)一系列資源的訪問

條件變量與信號(hào)量的異同

信號(hào)量利用條件變量捡絮、互斥鎖、計(jì)數(shù)器實(shí)現(xiàn)莲镣,計(jì)數(shù)器就是信號(hào)量的核心福稳,信號(hào)量是條件變量的高級(jí)抽象

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瑞侮,隨后出現(xiàn)的幾起案子的圆,更是在濱河造成了極大的恐慌,老刑警劉巖区岗,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件略板,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡慈缔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門种玛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來藐鹤,“玉大人瓤檐,你說我怎么就攤上這事∮榻冢” “怎么了挠蛉?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肄满。 經(jīng)常有香客問我谴古,道長,這世上最難降的妖魔是什么稠歉? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任掰担,我火速辦了婚禮,結(jié)果婚禮上怒炸,老公的妹妹穿的比我還像新娘带饱。我一直安慰自己,他們只是感情好阅羹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布勺疼。 她就那樣靜靜地躺著,像睡著了一般捏鱼。 火紅的嫁衣襯著肌膚如雪执庐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天导梆,我揣著相機(jī)與錄音耕肩,去河邊找鬼。 笑死问潭,一個(gè)胖子當(dāng)著我的面吹牛猿诸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狡忙,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼梳虽,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了灾茁?” 一聲冷哼從身側(cè)響起窜觉,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎北专,沒想到半個(gè)月后禀挫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡拓颓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年语婴,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡砰左,死狀恐怖匿醒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情缠导,我是刑警寧澤廉羔,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站僻造,受9級(jí)特大地震影響憋他,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜髓削,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一竹挡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔬螟,春花似錦此迅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鲁猩,卻和暖如春坎怪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背廓握。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工搅窿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人隙券。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓男应,卻偏偏與公主長得像,于是被迫代替她去往敵國和親娱仔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沐飘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容