多核程序設計課件4-Linux多線程編程_第1頁
多核程序設計課件4-Linux多線程編程_第2頁
多核程序設計課件4-Linux多線程編程_第3頁
多核程序設計課件4-Linux多線程編程_第4頁
多核程序設計課件4-Linux多線程編程_第5頁
已閱讀5頁,還剩52頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

多核程序設計課件4-Linux多線程編程多核程序設計課件4-Linux多線程編程多核程序設計課件4-Linux多線程編程標準的誕生和的發(fā)展密不可分各廠家對的開發(fā)各自為政,造成了的版本相當混亂,給軟件的可移植性帶來很大困難,對的發(fā)展極為不利可移植操作系統(tǒng)接口:電氣和電子工程師協(xié)會(,)開發(fā)提高環(huán)境下應用程序的可移植性許多其它的操作系統(tǒng),例如,都支持標準標準的誕生和的發(fā)展密不可分各廠家對的開發(fā)各自為政,造成了的版本相當混亂,給軟件的可移植性帶來很大困難,對的發(fā)展極為不利可移植操作系統(tǒng)接口:電氣和電子工程師協(xié)會(,)開發(fā)提高環(huán)境下應用程序的可移植性許多其它的操作系統(tǒng),例如,都支持標準線程庫介紹標準p1003.1c()定義了處理線程的一系列C語言類型的。線程是線程的標準,定義了創(chuàng)建和操縱線程的一套在中,線程一般被認為是“輕量級的進程”。創(chuàng)建進程所使用的函數(shù)是()或者()。而對線程的創(chuàng)建和管理,可以使用的線程庫提供的。提供的多線程和多進程執(zhí)行環(huán)境主要目的是提高系統(tǒng)資源利用率和任務的并發(fā)或并行程度。針對操作系統(tǒng),也存在一個開放源代碼的版本,稱為32

庫線程的創(chuàng)建線程庫中提供的創(chuàng)建線程的函數(shù)是(),函數(shù)原型是:(*,*,*(*)(*),*);第一個參數(shù)是類型的指針,這個指針指向用來存放當線程創(chuàng)建成功后的所創(chuàng)建的線程的標志第二個參數(shù)表明被創(chuàng)建的線程可以擁有的屬性第三個參數(shù)是一函數(shù)指針,此函數(shù)指針指向線程的實現(xiàn)函數(shù)第四個參數(shù)是*類型的,此參數(shù)指向實際線程處理函數(shù)執(zhí)行的時候所需要的參數(shù)庫(續(xù))線程的退出在線程的處理函數(shù)中,可以顯式的調用()結束線程執(zhí)行。()函數(shù)的函數(shù)原型是:(*);參數(shù)是指向線程的返回值線程的退出不能簡單使用()函數(shù),因為一旦使用了()函數(shù),實際上是整個進程的退出,會導致其他線程也隨著進程的消亡而消亡庫(續(xù))等待線程結束線程創(chuàng)建完畢后,創(chuàng)建線程的線程,就可以使用()函數(shù)等待被創(chuàng)建的線程的結束。()函數(shù)會掛起創(chuàng)建線程的線程的執(zhí)行,直到等待到想要等待的子線程。()函數(shù)的函數(shù)原型是:(,**);第一個參數(shù)是需要等待的線程的標志如果不為空,那么指向返回的值調用()函數(shù)的目的是釋放相關內存資源庫(續(xù))線程的分離()函數(shù)雖然可以等待被創(chuàng)建的線程的結束,且可以回收被創(chuàng)建的線程的相關內存資源,但是這個函數(shù)的主要缺點是要掛起調用()的線程。線程庫提供了一個函數(shù)(),使得子線程本身自己有自我回收內存資源的能力。此函數(shù)的原型是:();這個函數(shù)的目的是讓線程可以處于分離()狀態(tài)處于分離狀態(tài)的線程有能力在自己結束執(zhí)行的時候回收相關的內存資源庫(續(xù))獲得當前線程標志使用()函數(shù)可以獲得當前線程的標志,()的返回值就是當前線程的標志。其函數(shù)原型是:();線程的撤銷一個線程可以通過向另個線程發(fā)送“請求”來結束另一個線程的執(zhí)行。()函數(shù)可以完成這個功能。接收撤銷請求的線程并不是“隨便”就結束了自己的執(zhí)行,它可以忽略、推遲、或者立即響應別的線程發(fā)來的結束線程執(zhí)行的請求,這取決于線程設置。這里的“推遲”是指線程執(zhí)行到撤銷點()的時候,才執(zhí)行線程的撤銷操作。庫中關于撤銷操作的函數(shù)有:(,*);(,*);();線程的撤銷(續(xù))使用線程撤銷相關的操作的例子<><><><>2=;=;[];*1(*){(,);();(5);("1\n");/*是一撤銷點,1在這里等待條件變量的滿足*/(,);();();}線程的撤銷(續(xù))*2(*){i=0;("21\n");/*向線程1發(fā)送撤銷請求*/([0]);("2\n");();}(,*[]){i;;=([0],,1,);(0){("!\n");(1);}=([1],,2,);(0){("!\n");(1);}線程的撤銷(續(xù))(i=0;i<;){=([i],);(0){("!\n");(1);}}();();0;}程序運行結果:2121在撤銷線程的時候,可以編寫程序讓線程進一步進行所謂的“清理”工作,比如已經(jīng)擁有了某個,在清理例程中可以釋放這個;如果動態(tài)分配了內存,那么可以在清理例程中釋放動態(tài)分配的內存。使用編寫的程序例子一個簡單的多線程程序,其創(chuàng)建了兩個幾乎一樣的線程<><><><>21=2,2=3;*1(*){ *=(*);(1);("\n",);(1);}*2(*){*=(*);(2);("\n",);(2);}使用編寫的程序例子(續(xù))(,*[]){i;;*[2];/*申明類型的數(shù)組用來存放創(chuàng)建線程得到的線程的標志。這里創(chuàng)建的兩個線程,分別傳遞了不同的參數(shù),分別[0]和[1]指向所要傳遞的字符串起始地址。*/[];*[];[0]="1";[1]="2";("...\n");/*使用()分別創(chuàng)建了兩個線程。創(chuàng)建線程的時候,()的第二個參數(shù)是,表示被創(chuàng)建的線程擁有缺省的屬性:被創(chuàng)建的線程是處于可加入狀態(tài),且其調度機制是普通的非實時的*/=([0],,1,(*)[0]);(0){("!\n");(1);=([1],,2,(*)[1]);(0){("!\n");(1);}使用編寫的程序例子(續(xù))(",.\n");("...\n");/*主線程使用()等待兩個子線程的結束。其中,[0]和[1]分別指向兩個線程通過調用()返回的值。*/(i=0;i<;){=([i],(**)[i]);(0){("!\n");(1);}{("\n",*[i]);}}0;}在中,編譯線程相關的程序的時候需要用到庫。比如要編譯為可執(zhí)行程序,那么可以這樣使用來編譯:–線程的屬性()創(chuàng)建線程的時候,如果第二個參數(shù)是那么使用缺省的線程屬性。線程的屬性名和其含義可以在下表中看到屬性名意義

選擇被創(chuàng)建的線程是處于可加入的狀態(tài)還是分離狀態(tài)??杉尤霠顟B(tài)值是;分離狀態(tài)值是。缺省狀態(tài)值是。()可設置線程為加入或者分離狀態(tài);()可以獲得當前線程是否是加入的或者是分離的狀態(tài)。

為被創(chuàng)建的線程選擇調度策略。被創(chuàng)建的線程的狀態(tài)可以是(一般的,非實時調度)、(實時,輪轉調度)或者(實時,先進先出調度)。缺省值是。實時調度和只能用于有超級用戶權限的進程使用。()和()函數(shù)可以設置和獲得線程的調度屬性。

為被創(chuàng)建的線程選擇調度參數(shù)。這里的調度參數(shù)指的是線程的調度優(yōu)先級。缺省優(yōu)先級是0。這個屬性對于是不重要的;它只對和兩個和實時調度相關的調度方式有效。()和()兩個函數(shù)可以分別對線程的優(yōu)先級進行設置和獲取。(注釋:在中為:

{;};)

選擇對新創(chuàng)建的線程的調度策略和調度參數(shù)是否被和屬性決定(這時的值是)或者是通過父線程繼承而得到的(這時的值是)。缺省的值是。

為選擇被創(chuàng)建的線程調度競爭范圍。缺省值是,表示線程和系統(tǒng)的所有的其他運行在上的進程爭奪資源。如果是,表示調度的競爭只發(fā)生在運行于同一進程空間的線程之間,線程的優(yōu)先級只在同一進程空間的線程之間有效,和其他進程無關。使用庫創(chuàng)建線程的特點線程可使用存在于進程中的資源,因此創(chuàng)建線程比創(chuàng)建進程更快。線程間的通信方式更容易,比如通過進程中的變量,可以讓多個線程共享數(shù)據(jù)。操作系統(tǒng)對線程的切換比對進程的切換更容易和快速線程互斥和同步——可以用來保護并發(fā)讀寫操作中的共享的數(shù)據(jù)結構,實際上用可以用來實現(xiàn)臨界代碼區(qū)。對于有如下特性:原子性。對的加鎖和解鎖操作是原子的,一個線程進行操作的過程中,其他線程不能對同一個進行其他操作。單一性。擁有的線程除非釋放,否則其他線程不能擁有此。非忙等待。等待的線程處于等待狀態(tài),直到要等待的處于未加鎖狀態(tài),這時操作系統(tǒng)負責喚醒等待此的線程。本身只能有兩種可能的狀態(tài):鎖定或未鎖定當互斥量處于已加鎖狀態(tài)時,其所保護的代碼段是不可訪問的在使用的時候,首先必須初始化。在使用的時候,如果程序編寫不當,可能會出現(xiàn)“死鎖”現(xiàn)象線程互斥和同步——(續(xù))在線程庫中,存在三種類型的,分別是快速()、遞歸()和錯誤檢測()??焖伲喝绻幸粋€線程鎖定了,那么其他線程如果想要獲得此,必須等待處于未鎖定狀態(tài)遞歸:已經(jīng)擁有此的線程可執(zhí)行多次加鎖操作,且不必等待處于未鎖狀態(tài),但是對于其他線程,要想獲得此,必須等待當此處于未鎖定狀態(tài)擁有遞歸的線程加鎖的次數(shù)應該和解鎖的次數(shù)相同錯誤檢測:如果錯誤檢測已經(jīng)被一個線程鎖定,那么其他線程想要鎖定這個,使用()函數(shù)將返回線程互斥和同步——(續(xù))線程庫對提供了以下函數(shù)進行操作:(*,*);(*);(*);(*);(*);線程使用的簡單代碼如下所示:;=;();/**/();線程互斥和同步——(續(xù))()用來初始化,并且使用參數(shù)來傳遞初始化需要定義的屬性。()用來獲得如果當前線程想要獲取的已經(jīng)被其他線程鎖定,且是快速,那么調用()將使得當前線程處于等待狀態(tài);如果是遞歸,那么()立即返回,并記錄本線程鎖定此的次數(shù),相同次數(shù)的()必須作用于此,然后此才能處于未鎖狀態(tài);如果是錯誤檢測,如果已經(jīng)處于鎖定狀態(tài),其他線程嘗試()將立即返回錯誤。()函數(shù)和()函數(shù)功能基本一致,只不過此函數(shù)是“嘗試”獲得,如果不能獲得,其將立刻返回,并繼續(xù)線程的執(zhí)行()函數(shù)用來釋放鎖,以便供其他線程使用。在使用完畢后,應該使用()函數(shù)來釋放資源。線程互斥和同步——(續(xù))使用常見的錯誤是加鎖和解鎖不匹配或者位置不當。例如:線程A先使得1處于鎖定狀態(tài),然后線程B使得2處于鎖定狀態(tài)。假設1和2都是快速鎖,那么當線程A要往2上加鎖的時候,線程A此時只能等待。而線程B也要獲得1,但是1已經(jīng)處于鎖定狀態(tài),且線程A由于在等待2解鎖,故線程B也處于等待狀態(tài),這樣一來,線程A和線程B都不能繼續(xù)執(zhí)行,造成了所謂的“死鎖”。線程互斥和同步——(續(xù))在同一線程中,線程在沒有釋放的情況下再次試圖加鎖在以上代碼中,線程在獲得1后,使得1處于加鎖狀態(tài),然后調用函數(shù)f(x),此函數(shù)又在程序中使用()函數(shù)試圖加鎖1,這樣的結果是線程無法繼續(xù)往下執(zhí)行pthread_mutex_lock(&mutex1);

f(x);

pthread_mutex_unlock(&mutex1);

pthread_mutex_lock(&mutex1);

pthread_mutex_unlock(&mutex1);線程互斥和同步事件通信模型容易導致錯誤模型沒有提供及的事件機制在概念上直接對應的功能條件變量信號量線程互斥和同步——條件變量條件變量是線程的同步設備。在線程間使用條件變量可以使得一個線程在執(zhí)行過程中,因滿足某個條件而發(fā)出信號通知另一個線程;而另一個線程可以處于掛起狀態(tài),等待某個條件的滿足后,才繼續(xù)執(zhí)行。多用于存在一個或多個線程等待數(shù)據(jù)項的值發(fā)生改變的情況線程不是“旋轉”而是阻塞在條件變量上,等待該條件變量被其他線程激發(fā)該激發(fā)信號通知這些等待線程數(shù)據(jù)項的值已經(jīng)被修改,并使其開始或者恢復其處理過程條件變量必須和一起使用來避免競爭情況。相關的操作函數(shù)如下:=;(*,*);(*);(*);(*,*);(*,*,*);(*);線程互斥和同步——條件變量()函數(shù)用來初始化條件變量()啟動等待指向的條件變量的一個線程如果沒有線程等待條件變量,什么也不會發(fā)生;如果有多個線程等待條件此條件變量,那么只有一個線程被重新啟動執(zhí)行,但是到底那個線程先啟動執(zhí)行,并沒有指定()函數(shù)啟動所有的等待條件變量的線程()原子性地解鎖其第二個參數(shù)指向的,然后等待條件變量條件的滿足()是在規(guī)定的時間內等待條件的滿足()是無限制地等待()釋放條件變量所占的資源線程互斥和同步——條件變量(續(xù))使用條件變量的例子<><><><>2/*初始化條件變量*/=;/*初始化*/=;*1(*){();("1\n");("1...\n");(,);("1!\n");();("1\n");();}線程互斥和同步——條件變量(續(xù))*2(*){i=0;,;();=;();("2\n");

/*休眠5秒鐘*/(-<5){(1);();;("2\n",i);}("1...\n");/*啟動等待條件變量的其他線程*/();();("2\n");();}線程互斥和同步——條件變量(續(xù))(i=0;i<;){=([i],);(0){("!\n");(1);}}0;}程序執(zhí)行結果:11...221222324251...21!1信號量信號量在多線程編程中可以起到同步或互斥的作用。用信號量可以實現(xiàn)傳統(tǒng)操作系統(tǒng)P、V操作。由于信號量不是內核負責維護,所以當進程退出后,信號量自動消亡。對信號量的操作函數(shù)有:<>(*,,);(*);(*);(*);(*,*);(*);信號量(續(xù))()用來初始化信號量,第三個參數(shù)是信號量計數(shù)()阻塞當前線程的執(zhí)行,直到信號量的計數(shù)非0;然后,它會把信號量計數(shù)減1,然后程序繼續(xù)執(zhí)行,相當于P操作(),把指向的信號量計數(shù)加1,相當于V操作()用來釋放信號量資源對()函數(shù)來說,如果信號量值是大于0的,那么信號量值原子性地減少1,并立即返回0;如果信號量值等于0,其立即返回,并且得到錯誤類型為的錯誤。()函數(shù)得到當前信號量的值P操作和V操作是執(zhí)行時不被打斷的兩個操作系統(tǒng)原語信號量(續(xù))一個簡單的生產(chǎn)者消費者例子來說明信號量操作的相關函數(shù)的用法<><><><><><>;3;{[];,,;};;*(*),*(*);信號量(續(xù))(,**){,;(2){<<":"<<;(0);}=([1]);(,0,1);(,0,);(,0,0);(,,,);(,,,);(,);(,);();();();(0);}信號量(續(xù))*(*){i;(i=0;i<;){();();[i%]=i;<<""<<[i%]<<;();();}();}*(*){i;(i=0;i<;){();();([i%]i)<<"["<<i<<"]="<<[i%]<<;<<":"<<[i%]<<;信號量(續(xù))();();}();}程序執(zhí)行結果:012:0:1:2345:3:4:5678:6:7:89:9線程和信號處理庫也對線程對信號的處理提供了一些函數(shù),這些函數(shù)包括:(,*,*‐);(,);(*,*);()函數(shù)用來改變或者設置線程的信號屏蔽()()函數(shù)可以向其他線程發(fā)送信號()掛起調用()的線程,直到收到第一個參數(shù)指向的信號集中指定的信號,且等待到信號被存放到第二個參數(shù)指向的位置線程和信號處理(續(xù))在中,使用數(shù)據(jù)類型存放信號集合。對信號集合的操作的C提供了一些函數(shù):(*);(*);(*,);(*,);(*,);()把指向的信號集清空()初始化信號集讓其包括所有的信號()把信號添加到信號集中()是從信號集刪除信號()用來判斷某個信號是否在信號集中線程和信號處理(續(xù))對以上函數(shù)的使用的一個例子這個例子創(chuàng)建兩個線程,線程2向線程1發(fā)送信號1和2。線程2先向線程1發(fā)送1信號,然后再發(fā)送2信號。線程1收到1信號的時候,線程1使用()對1進行阻塞,故1信號在解除1阻塞之前并沒有調用信號處理函數(shù)()處理信號1,此時1信號變成未決信號(),當線程1調用(,,)時,恢復線程1原來的信號屏蔽,這個時候未決信號1被處理。線程1收到2時,并沒有調用信號處理函數(shù)()盡管1和2都使用()函數(shù)進行了注冊,原因是線程1使用()等待2信號。線程和信號處理(續(xù))<><><><><>2=;=;[];/*信號處理函數(shù),可以處理信號1和2*/(){(){1:(":1!\n",());;2:(":2!\n",());;:;}}線程和信號處理(續(xù))*1(*){,,;;;();();

/*初始化信號集,等待2的過程中,阻塞1信號*/(,1);/*初始化信號集,等待信號2*/(,2);("1's\n",());

/*阻塞1信號*/=(,,);(0){("\n");(0);}線程和信號處理(續(xù))("1...\n");/*等待2信號*/(,);(2){("112!\n");}/*恢復老的信號屏蔽*/=(,,);(0){("!");}(0);}*2(*){(1);("2's\n",());/*向線程1發(fā)送1信號*/([0],1);("211!\n");(1);/*向線程1發(fā)送2信號*/([0],2);("221!\n");(0);}線程和信號處理(續(xù))(,*[]){i;;/*注冊信號1和2*/(1,);(2,);/*創(chuàng)建線程*/=([0],,1,);(0){("!\n");(1);}=([1],,2,);(0){("!\n");(1);}/*等待線程結束*/(i=0;i<;){=([i],);(0){("!\n");(1);線程和信號處理(續(xù))}}/*釋放和條件變量占有的資源*/();();0;}程序的執(zhí)行結果:1's30852207841...2's3076828080211!221!112!3085220784:1!使用調試線程以及線程的調優(yōu)主要可以完成下面四個方面的功能:啟動程序,可以按照你的自定義的要求隨心所欲的運行程序??勺尡徽{試的程序在所指定的調置的斷點處停住。(斷點可以是條件表達式)當程序被停住時,可以檢查此時程序中所發(fā)生的事。動態(tài)的改變程序的執(zhí)行環(huán)境。使用調試線程以及線程的調優(yōu)在軟件開發(fā)中,是一個功能強大、運行穩(wěn)定的程序調試工具。不僅僅可以調試單進程程序,也可以調試多進程、多線程程序。運行可以看到:$6.42005,.,,.""..""."i486".()

使用調試線程以及線程的調優(yōu)提供了一些命令,可以跟縱程序的執(zhí)行。在使用調試程序之前,可執(zhí)行程序編譯選項應該加上,這樣的話可執(zhí)行程序內就被編譯器添加了相關的符號信息,便于用戶使用調試程序。要對使用條件變量的例子進行調試,首先可以啟動:$6.4......()啟動后,被帶入的調試環(huán)境中,就可以使用的命令開始調試程序了,的命令可以使用命令來查看在中,運行程序使用r或是命令使用調試線程以及線程的調優(yōu)當以方式啟動后,會在路徑和當前目錄中搜索的源文件。如要確認是否讀到源文件,可使用l或命令,看看是否能列出源代碼。輸入命令l或者可以查看源代碼:()52("2\n");53();54}5556(,*[])57{58i;59;60[];61=([0],,1);()使用調試線程以及線程的調優(yōu)現(xiàn)在讓程序執(zhí)行,在()提示后輸入命令r或者,程序開始運行:()r:10[][-1209547072(15283)][-1209547072(15283)]1,(1,03004):6161=([0],,1,);()程序的運行需要設置下面的參數(shù)程序運行參數(shù)運行環(huán)境工作目錄程序的輸入輸出程序運行到了斷點處就停止了執(zhí)行。如果要單步執(zhí)行,可以輸入命令n或者比如:()n[-1209549904(15305)]62(0){()使用調試線程以及線程的調優(yōu)使用命令b或者來設置斷點。比如先設置斷點為函數(shù)入口:()b10x8048851:,61.()設置斷點的方法:在進入指定函數(shù)時停?。涸谥付ㄐ刑柾W。涸诋斍靶刑柕那懊婊蚝竺娴男型W?。為自然數(shù):在源文件的行處停住:在源文件的函數(shù)的入口處停住。*:在程序運行的內存地址處停住。:命令沒有參數(shù)時,表示在下一條指令處

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論