久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久

當前位置:首頁 > 嵌入式培訓 > 嵌入式學習 > 講師博文 > Linux多線(xian)程與同(tong)步

Linux多(duo)線程與同(tong)步 時(shi)間:2018-09-29      來(lai)源:未(wei)知(zhi)

典型的UNIX系統都支持一個進(jin)程(cheng)(cheng)(cheng)(cheng)(cheng)創建多(duo)個線(xian)程(cheng)(cheng)(cheng)(cheng)(cheng)(thread)。在(zai)Linux進(jin)程(cheng)(cheng)(cheng)(cheng)(cheng)基礎中(zhong)提到,Linux以(yi)進(jin)程(cheng)(cheng)(cheng)(cheng)(cheng)為單位組織操作,Linux中(zhong)的線(xian)程(cheng)(cheng)(cheng)(cheng)(cheng)也都基于進(jin)程(cheng)(cheng)(cheng)(cheng)(cheng)。盡管實(shi)現方式有異于其它的UNIX系統,但Linux的多(duo)線(xian)程(cheng)(cheng)(cheng)(cheng)(cheng)在(zai)邏(luo)輯和使用上與真正的多(duo)線(xian)程(cheng)(cheng)(cheng)(cheng)(cheng)并(bing)沒有差別(bie)。

在Linux從程(cheng)序到進(jin)(jin)程(cheng)中(zhong)提到的(de)(de)(de)(de)stack的(de)(de)(de)(de)功能和(he)用(yong)(yong)途。由于stack中(zhong)只有(you)(you)下方(fang)的(de)(de)(de)(de)stack frame可(ke)以(yi)(yi)被讀(du)取,所以(yi)(yi)我(wo)們(men)只能有(you)(you)該(gai)frame對(dui)應的(de)(de)(de)(de)單(dan)一函數處(chu)于激活狀態。為(wei)了實現多線(xian)程(cheng),我(wo)們(men)必須繞開stack帶給我(wo)們(men)的(de)(de)(de)(de)限制。為(wei)此(ci),當(dang)我(wo)們(men)創建一個(ge)(ge)新的(de)(de)(de)(de)線(xian)程(cheng)的(de)(de)(de)(de)時(shi)候,我(wo)們(men)為(wei)這(zhe)個(ge)(ge)線(xian)程(cheng)創建一個(ge)(ge)新的(de)(de)(de)(de)stack。當(dang)該(gai)stack執行到全部(bu)彈(dan)出的(de)(de)(de)(de)時(shi)候,該(gai)線(xian)程(cheng)完成任務并(bing)結束。所以(yi)(yi),多線(xian)程(cheng)的(de)(de)(de)(de)進(jin)(jin)程(cheng)在內存中(zhong)會有(you)(you)多個(ge)(ge)stack,相互(hu)之間(jian)以(yi)(yi)一定的(de)(de)(de)(de)空白區域(yu)隔開,以(yi)(yi)備stack的(de)(de)(de)(de)增長。每個(ge)(ge)線(xian)程(cheng)隨(sui)時(shi)可(ke)以(yi)(yi)使用(yong)(yong)自己stack中(zhong)下方(fang)的(de)(de)(de)(de)stack frame中(zhong)的(de)(de)(de)(de)參數和(he)變量,并(bing)與(yu)其它(ta)線(xian)程(cheng)共(gong)享內存中(zhong)的(de)(de)(de)(de)Text,heap和(he)global data區域(yu)。在上面(mian)的(de)(de)(de)(de)例子中(zhong),我(wo)們(men)將在進(jin)(jin)程(cheng)空間(jian)中(zhong)有(you)(you)三個(ge)(ge)stack。

(要(yao)注(zhu)意(yi)的是(shi),對(dui)于多(duo)線程來說(shuo),由于同一個(ge)進程空間中(zhong)存在多(duo)個(ge)stack,任何一個(ge)空白區域被(bei)填(tian)滿(man)都會導(dao)致stack overflow的問題。)

多(duo)(duo)線(xian)程相當于一(yi)個(ge)(ge)并(bing)發(concunrrency)系(xi)統(tong)(tong)。并(bing)發系(xi)統(tong)(tong)一(yi)般(ban)同(tong)時執(zhi)行多(duo)(duo)個(ge)(ge)任務。如(ru)果多(duo)(duo)個(ge)(ge)任務可以共(gong)享資源,特(te)別是同(tong)時寫入某個(ge)(ge)變(bian)量(liang)的時候,就需要(yao)解決(jue)同(tong)步的問題(ti)。比如(ru)說,我們(men)有一(yi)個(ge)(ge)多(duo)(duo)線(xian)程火車售(shou)票系(xi)統(tong)(tong),用(yong)全局變(bian)量(liang)i存儲剩余的票數。多(duo)(duo)個(ge)(ge)線(xian)程不(bu)斷地賣票(i = i - 1),直到剩余票數為0。所(suo)以每個(ge)(ge)都需要(yao)執(zhi)行如(ru)下操作:

/*mu is a global mutex*/

while (1) {                        /*infinite loop*/

    if (i != 0) i = i -1

    else {

      printf("no more tickets");

      exit();

    }

}

如(ru)果(guo)只(zhi)有一個(ge)(ge)線(xian)程(cheng)執(zhi)(zhi)行上面的(de)(de)程(cheng)序的(de)(de)時候(相當于(yu)一個(ge)(ge)窗口售票),則沒有問題。但如(ru)果(guo)多(duo)個(ge)(ge)線(xian)程(cheng)都執(zhi)(zhi)行上面的(de)(de)程(cheng)序(相當于(yu)多(duo)個(ge)(ge)窗口售票), 我(wo)們就會出現問題。我(wo)們會看到,其根(gen)本原因在于(yu)同時發生的(de)(de)各(ge)個(ge)(ge)線(xian)程(cheng)都可以對i讀(du)取和寫(xie)入。

我們這(zhe)里(li)的(de)(de)(de)(de)if結構會給CPU兩個(ge)(ge)指(zhi)令(ling), 一(yi)(yi)個(ge)(ge)是(shi)判斷是(shi)否有(you)剩余的(de)(de)(de)(de)票(piao)(piao)(piao)(i != 0), 一(yi)(yi)個(ge)(ge)是(shi)賣(mai)(mai)票(piao)(piao)(piao) (i = i -1)。某個(ge)(ge)線(xian)(xian)程(cheng)會先(xian)判斷是(shi)否有(you)票(piao)(piao)(piao)(比如說此時(shi)i為1),但兩個(ge)(ge)指(zhi)令(ling)之間(jian)存(cun)在(zai)一(yi)(yi)個(ge)(ge)時(shi)間(jian)窗口(kou),其(qi)它(ta)線(xian)(xian)程(cheng)可能(neng)在(zai)此時(shi)間(jian)窗口(kou)內(nei)執(zhi)行賣(mai)(mai)票(piao)(piao)(piao)操作(i = i -1),導致該(gai)線(xian)(xian)程(cheng)賣(mai)(mai)票(piao)(piao)(piao)的(de)(de)(de)(de)條件不再成(cheng)立。但該(gai)線(xian)(xian)程(cheng)由于已經執(zhi)行過了判斷指(zhi)令(ling),所以無(wu)從知道i發生(sheng)了變化,所以繼續執(zhi)行賣(mai)(mai)票(piao)(piao)(piao)指(zhi)令(ling),以至于賣(mai)(mai)出不存(cun)在(zai)的(de)(de)(de)(de)票(piao)(piao)(piao) (i成(cheng)為負數)。對于一(yi)(yi)個(ge)(ge)真實(shi)的(de)(de)(de)(de)售(shou)票(piao)(piao)(piao)系統來說,這(zhe)將成(cheng)為一(yi)(yi)個(ge)(ge)嚴重(zhong)的(de)(de)(de)(de)錯誤 (售(shou)出了過多(duo)的(de)(de)(de)(de)票(piao)(piao)(piao),火車爆滿(man))。

在(zai)并發情(qing)況(kuang)下,指(zhi)令執(zhi)行(xing)的(de)(de)(de)(de)先后順序由內(nei)(nei)核決(jue)(jue)定。同一個(ge)(ge)線程(cheng)內(nei)(nei)部,指(zhi)令按(an)照先后順序執(zhi)行(xing),但不(bu)同線程(cheng)之間的(de)(de)(de)(de)指(zhi)令很難(nan)說清除哪一個(ge)(ge)會先執(zhi)行(xing)。如果運(yun)行(xing)的(de)(de)(de)(de)結(jie)果依賴于不(bu)同線程(cheng)執(zhi)行(xing)的(de)(de)(de)(de)先后的(de)(de)(de)(de)話,那么就會造成競(jing)(jing)爭條(tiao)件(jian)(race condition),在(zai)這樣的(de)(de)(de)(de)狀況(kuang)下,計算機的(de)(de)(de)(de)結(jie)果很難(nan)預知。我們應該盡量避(bi)免競(jing)(jing)爭條(tiao)件(jian)的(de)(de)(de)(de)形成。常見的(de)(de)(de)(de)解(jie)決(jue)(jue)競(jing)(jing)爭條(tiao)件(jian)的(de)(de)(de)(de)方法(fa)是將原先分離的(de)(de)(de)(de)兩個(ge)(ge)指(zhi)令構成不(bu)可(ke)分隔(ge)的(de)(de)(de)(de)一個(ge)(ge)原子操(cao)作(atomic operation),而(er)其它(ta)任務(wu)不(bu)能插入到原子操(cao)作中。

3. 多進程(cheng)同步(synchronization)

對于(yu)多線(xian)程(cheng)(cheng)程(cheng)(cheng)序來說,同(tong)(tong)步是指在一定的時間(jian)內只允許某(mou)一個線(xian)程(cheng)(cheng)訪問某(mou)個資源 。而在此(ci)時間(jian)內,不允許其它的線(xian)程(cheng)(cheng)訪問該資源。我們可以通過互(hu)斥鎖(suo)(mutex),條件變(bian)量(condition variable)和(he)讀寫(xie)鎖(suo)(reader-writer lock)來同(tong)(tong)步資源。

1) mutex

mutex是(shi)一(yi)個(ge)特(te)殊的(de)變量,它(ta)有(you)(you)鎖(suo)上(lock)和打(da)開(unlock)兩個(ge)狀態(tai)。mutex一(yi)般被設置成(cheng)全局變量。打(da)開的(de)mutex可(ke)以(yi)由某個(ge)線(xian)程(cheng)(cheng)獲得。一(yi)旦獲得,這個(ge)mutex會鎖(suo)上,此后只(zhi)有(you)(you)該線(xian)程(cheng)(cheng)有(you)(you)權打(da)開。其(qi)它(ta)想(xiang)要獲得mutex的(de)線(xian)程(cheng)(cheng),會等(deng)(deng)(deng)待直到(dao)mutex再次打(da)開的(de)時候。我們可(ke)以(yi)將mutex想(xiang)像成(cheng)為一(yi)個(ge)只(zhi)能(neng)容納一(yi)個(ge)人(ren)的(de)洗手間,當某個(ge)人(ren)進入(ru)洗手間的(de)時候,可(ke)以(yi)從里面將洗手間鎖(suo)上。其(qi)它(ta)人(ren)只(zhi)能(neng)在mutex外(wai)面等(deng)(deng)(deng)待那個(ge)人(ren)出來,才能(neng)進去。在外(wai)面等(deng)(deng)(deng)候的(de)人(ren)并(bing)沒(mei)有(you)(you)排隊(dui),誰先看到(dao)洗手間空了,就可(ke)以(yi)首(shou)先沖(chong)進去。

上面的(de)問題很(hen)容易使(shi)用mutex的(de)問題解決,每個進程的(de)程序(xu)可以改為:

/*mu is a global mutex*/

while (1) {                /*infinite loop*/

  mutex_lock(mu);           /*aquire mutex and lock it, if cannot, wait until mutex is unblocked*/

  if (i != 0) i = i - 1;

  else {

    printf("no more tickets");

    exit();

  }

  mutex_unlock(mu);         /*release mutex, make it unblocked*/

}

第(di)一(yi)個執(zhi)行mutex_lock()的線(xian)(xian)程會(hui)先獲(huo)得(de)mu。其它想要獲(huo)得(de)mu的線(xian)(xian)程必須等待,直到第(di)一(yi)個線(xian)(xian)程執(zhi)行到mutex_unlock()釋放mu,才可(ke)以(yi)獲(huo)得(de)mu,并繼續執(zhi)行線(xian)(xian)程。所(suo)以(yi)線(xian)(xian)程在mutex_lock()和mutex_unlock()之間的操作時,不會(hui)被其它線(xian)(xian)程影響,就構成了(le)一(yi)個原子(zi)操作。

需要注意的(de)(de)時候,如(ru)果存在某個進程依(yi)然(ran)使用原(yuan)先的(de)(de)程序 (即不嘗(chang)試獲得mu,而直接修(xiu)改(gai)i),mutex不能阻止該程序修(xiu)改(gai)i,mutex就(jiu)失去了保護資源的(de)(de)意義(yi)。所以,mutex機(ji)制需要程序員(yuan)自己來寫出(chu)完善的(de)(de)程序來實現mutex的(de)(de)功能。我(wo)們下(xia)面講的(de)(de)其它機(ji)制也是如(ru)此(ci)。

2) condition variable

condition variable是另(ling)一種常(chang)用(yong)的變(bian)量。它也常(chang)常(chang)被保存為全局變(bian)量,并和mutex合作(zuo)。

假設我們(men)(men)有(you)這樣一(yi)個(ge)(ge)狀況: 我們(men)(men)有(you)100個(ge)(ge)工(gong)人(ren)(ren)(ren),每人(ren)(ren)(ren)負責裝修一(yi)個(ge)(ge)房(fang)(fang)間(jian)(jian)。當有(you)10個(ge)(ge)房(fang)(fang)間(jian)(jian)裝修完成的(de)時候,我們(men)(men)就通知相應(ying)的(de)十個(ge)(ge)工(gong)人(ren)(ren)(ren)一(yi)起去(qu)喝啤酒。我們(men)(men)如(ru)何實現呢(ni)?我們(men)(men)可(ke)以讓工(gong)人(ren)(ren)(ren)在裝修好房(fang)(fang)間(jian)(jian)之后,去(qu)檢(jian)查已經裝修好的(de)房(fang)(fang)間(jian)(jian)數。但多線(xian)程條(tiao)件下,會(hui)有(you)競爭(zheng)條(tiao)件的(de)危險(其他工(gong)人(ren)(ren)(ren)會(hui)在該(gai)工(gong)人(ren)(ren)(ren)裝修好房(fang)(fang)子和(he)檢(jian)查之間(jian)(jian)完成工(gong)作(zuo))。

/*mu: global mutex, cond: global codition variable, num: global int*/

mutex_lock(mu)

num = num + 1;                      /*worker build the room*/

if (num <= 10) {                     /*worker is within the first 10 to finish*/

    cond_wait(mu, cond);      ;      /*wait*/

    printf("drink beer");

}

else if (num = 11) {         &nbsp; &nbsp;    /*workder is the 11th to finish*/

  cond_broadcast(mu, cond);         /*inform the other 9 to wake up*/

}

mutex_unlock(mu);

通常(chang), condition variable除了要(yao)和mutex配合之外(wai),還需(xu)要(yao)和另一個(ge)全(quan)局(ju)變(bian)量配合(這里(li)的num, 也就是裝修好的房間數)。這個(ge)全(quan)局(ju)變(bian)量用來構成各個(ge)條件(jian)。

我們(men)讓工人在(zai)裝修好(hao)房間(jian)(jian)(num = num + 1)之后(hou),去檢查(cha)已(yi)經(jing)裝修好(hao)的房間(jian)(jian)數( num < 10 )。由于mu被鎖上,所以不(bu)會有其他(ta)工人在(zai)此期間(jian)(jian)裝修房間(jian)(jian)(改變(bian)num的值(zhi))。如果(guo)該工人是前(qian)十個完成的人,那么我們(men)就調(diao)用cond_wait()函數。

cond_wait()做兩(liang)件事情,一個(ge)是釋放(fang)mu,從而讓別的工人(ren)可以建房(fang)。另一個(ge)是等待,直到(dao)cond的通知。這樣(yang)的話,符(fu)合條件的線程就開始等待。當(dang)有通知(第十個(ge)房(fang)間(jian)已經修建好)到(dao)達的時候(hou),condwait()會再(zai)次(ci)鎖上mu,并(bing)恢復線程的運行(xing),我們會執行(xing)下一句prinft("drink beer") (我們以此(ci)來代表喝(he)啤(pi)酒)。此(ci)后直到(dao)mutex_unlock()就構(gou)成了另一個(ge)mutex結(jie)構(gou)。

那么(me)如何(he)讓(rang)前面十個(ge)調(diao)用cond_wait()的(de)(de)線程得到通(tong)(tong)知(zhi)呢?我們注意到if還有另一種可能(neng),也就(jiu)是修(xiu)建好第11個(ge)房間(jian)的(de)(de)人負(fu)責(ze)調(diao)用cond_broadcast()。它(ta)會給所有調(diao)用cond_wait()的(de)(de)進(jin)程放送通(tong)(tong)知(zhi),以(yi)便讓(rang)那些進(jin)程恢復(fu)運行。

Condition variable特別適用(yong)于(yu)多(duo)個(ge)線程(cheng)等(deng)待某個(ge)條件的發(fa)生。如果(guo)不(bu)使用(yong)Condition variable,那(nei)么每(mei)個(ge)進程(cheng)就(jiu)需要不(bu)斷嘗試獲(huo)得mutex并檢查條件是否(fou)發(fa)生,這樣大大浪費了系統的資源。

3) reader-writer lock

Reader-writer lock與mutex非常相似(si)。r、RW lock有三(san)種狀態(tai): 共享(xiang)讀取鎖(shared-read), 互斥寫入鎖(exclusive-write lock), 打開(kai)(unlock)。后(hou)兩(liang)種狀態(tai)與之前的(de)mutex兩(liang)種狀態(tai)完全相同(tong)。

一個unlock的RW lock可以被某個進程獲取R鎖或者W鎖。

如果被一個進(jin)(jin)程獲(huo)得(de)R鎖,RW lock可以被其(qi)它進(jin)(jin)程繼(ji)續(xu)獲(huo)得(de)R鎖,而(er)不必(bi)等待該進(jin)(jin)程釋(shi)放(fang)R鎖。但(dan)是,如果此時有(you)其(qi)它進(jin)(jin)程想要(yao)獲(huo)得(de)W鎖,它必(bi)須(xu)等到所(suo)有(you)持有(you)共(gong)享讀取鎖的進(jin)(jin)程釋(shi)放(fang)掉各(ge)自(zi)的R鎖。

如果(guo)一個鎖(suo)被一個進(jin)程(cheng)獲得(de)W鎖(suo),那么其(qi)它進(jin)程(cheng),無論是想要獲取(qu)R鎖(suo)還是W鎖(suo),都必須(xu)等待該(gai)進(jin)程(cheng)釋放W鎖(suo)。

這樣,多(duo)個(ge)進程就可以同(tong)時讀取(qu)共(gong)享(xiang)資(zi)源。而(er)具有危險性的寫入(ru)操作(zuo)則得(de)到了(le)互斥(chi)鎖的保護(hu)。

我(wo)(wo)(wo)們(men)需要同(tong)步并發系(xi)統,這為程(cheng)序員編程(cheng)帶來(lai)了難度。但是多(duo)(duo)線(xian)程(cheng)系(xi)統可以很好的(de)解決許多(duo)(duo)IO瓶(ping)頸的(de)問題(ti)。比(bi)如我(wo)(wo)(wo)們(men)監(jian)聽(ting)網絡端口。如果(guo)我(wo)(wo)(wo)們(men)只有一個線(xian)程(cheng),那么我(wo)(wo)(wo)們(men)必須監(jian)聽(ting),接(jie)收請求,處(chu)(chu)理(li),回復(fu),再監(jian)聽(ting)。如果(guo)我(wo)(wo)(wo)們(men)使(shi)用多(duo)(duo)線(xian)程(cheng)系(xi)統,則可以讓多(duo)(duo)個線(xian)程(cheng)監(jian)聽(ting)。當(dang)我(wo)(wo)(wo)們(men)的(de)某個線(xian)程(cheng)進行處(chu)(chu)理(li)的(de)時(shi)候,我(wo)(wo)(wo)們(men)還(huan)(huan)可以有其(qi)他(ta)的(de)線(xian)程(cheng)繼續監(jian)聽(ting),這樣,就(jiu)大大提高了系(xi)統的(de)利(li)用率。在數(shu)據越(yue)來(lai)越(yue)大,服務(wu)器(qi)讀(du)寫操作(zuo)越(yue)來(lai)越(yue)多(duo)(duo)的(de)今(jin)天,這具有相當(dang)的(de)意義(yi)。多(duo)(duo)線(xian)程(cheng)還(huan)(huan)可以更有效地利(li)用多(duo)(duo)CPU的(de)環境。

(就像做(zuo)飯(fan)一樣,不斷切換(huan)去處理不同的菜(cai)。) 

總結:

multiple threads, multiple stacks

race condition

mutex, condition variable, RW lock

上一篇:程序跳轉之longjmp

下一篇:WRTnode進階篇: usb設備移植

熱點文章推薦
華(hua)清學員(yuan)就(jiu)業榜單
高薪學員(yuan)經驗分享
熱點新聞(wen)推薦(jian)
前臺專線:010-82525158 企業培訓洽談專線:010-82525379 院校合作(zuo)洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技集團有限公司 版權所有 ,,京公海網安備11010802025203號

回到頂部