|   Linux下多線程的應用  時間(jian):2017-01-05作者:華清遠見 一、創建線程 函數簡介 phread_create是UNIX環(huan)境創建線(xian)程函數 頭文件 #include<pthread.h> 函數聲明 
	int pthread_create(pthread_t *restrict tidp 返回值 若成功則返回0,否則返回出錯編號 返回成功(gong)時,由tidp指向的(de)(de)內存(cun)單元被設(she)置為新創建(jian)線(xian)程的(de)(de)線(xian)程ID。attr參數(shu)(shu)(shu)(shu)(shu)用于制定各種不(bu)同(tong)的(de)(de)線(xian)程屬(shu)性(xing)。新創建(jian)的(de)(de)線(xian)程從start_rtn函(han)數(shu)(shu)(shu)(shu)(shu)的(de)(de)地址開始運(yun)行,該函(han)數(shu)(shu)(shu)(shu)(shu)只有一個空指針(zhen)參數(shu)(shu)(shu)(shu)(shu)arg,如果需(xu)要(yao)(yao)像start_rtn函(han)數(shu)(shu)(shu)(shu)(shu)傳遞(di)的(de)(de)參數(shu)(shu)(shu)(shu)(shu)不(bu)止一個,那么(me)需(xu)要(yao)(yao)把這些參數(shu)(shu)(shu)(shu)(shu)放到一個結構體中,然后把這個結構的(de)(de)地址作為arg的(de)(de)參數(shu)(shu)(shu)(shu)(shu)傳入。 linux下用c開發多線程(cheng)(cheng)程(cheng)(cheng)序,linux系統(tong)下的多線程(cheng)(cheng)遵循(xun)POSIX線程(cheng)(cheng)接口(kou),稱為pthread。 參數 
	第一參數為指向線程標識符的指針 另外,在編譯時注意加上(shang)-lpthread參數,以(yi)調(diao)用(yong)靜態連接庫。因(yin)為pthread并(bing)非linux系(xi)統的默認庫。 二、pthread_join 函數(shu)pthread_join用來等待一個線(xian)程(cheng)的結束。函數(shu)原型為: extern int phread_join (pthead_t __th,void **_thread_return); 第一個(ge)(ge)參數(shu)為(wei)被(bei)等(deng)待(dai)的(de)(de)線程標(biao)識符。第二個(ge)(ge)參數(shu)為(wei)一個(ge)(ge)用戶(hu)定義的(de)(de)指針,它(ta)可以用來存儲被(bei)等(deng)待(dai)線程的(de)(de)返(fan)會值。這個(ge)(ge)函(han)數(shu)是(shi)一個(ge)(ge)線程阻塞的(de)(de)函(han)數(shu),調用它(ta)的(de)(de)函(han)數(shu)將一直等(deng)待(dai)到被(bei)等(deng)待(dai)的(de)(de)線程結束為(wei)止,當函(han)數(shu)返(fan)回(hui)時(shi),被(bei)等(deng)待(dai)線程的(de)(de)資源被(bei)收(shou)回(hui)。如果(guo)執行成功,將返(fan)回(hui)0,如果(guo)失(shi)敗(bai)則返(fan)回(hui)一個(ge)(ge)錯誤(wu)號(hao)。 在linux中,默(mo)認情況下是(shi)在一個線(xian)程(cheng)被創建后,必(bi)須使用此函數對(dui)創建的線(xian)程(cheng)進行資源(yuan)回收,但是(shi)可以(yi)設(she)置Threads attributes來(lai)設(she)置當一個線(xian)程(cheng)結束時(shi),直接(jie)回收此線(xian)程(cheng)所占用的系統資源(yuan)。 三、 互斥鎖pthread_mutex_t的使用(yong) 1.兩種方法創建互斥鎖,靜態方式和動態方式。 POXIX定義(yi)了(le)一個(ge)(ge)PTHREAD_MUTEX_INITIALIZER來靜態初始(shi)化互斥(chi)鎖(suo),方法如下:phread_mutex_t mutex=PTHREAD_MUTEX_INITALIZER;在LinuxThreads實(shi)現中(zhong),pthread_mutex_t是一個(ge)(ge)結(jie)(jie)構,而PTHREAD_MUTEX_INITIALIZER則是一個(ge)(ge)結(jie)(jie)構常(chang)量(liang)。 動態方(fang)式是采(cai)用pthread_mutex_init()函數(shu)來初始化互(hu)斥鎖,API定義如下: int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr)其中mutexattr用(yong)于(yu)指定互斥(chi)屬(shu)(shu)性(見下),如果為(wei)NULL則使用(yong)缺省(sheng)屬(shu)(shu)性。 pthread_mutex_destroy()用(yong)(yong)于(yu)注銷一個(ge)(ge)互斥鎖,API定(ding)義如(ru)下:int pthread_mutex_destory(pthread_mutex_t *mutex) 銷毀一個(ge)(ge)互斥鎖即意味著(zhu)釋放它所占用(yong)(yong)的資(zi)源(yuan),且要求(qiu)鎖當(dang)前處于(yu)開發狀(zhuang)態(tai)。由于(yu)在linux中,互斥鎖并不占用(yong)(yong)任何資(zi)源(yuan),因此LinuxThreads中的pthread_mutex_destroy()除了檢查鎖狀(zhuang)態(tai)以外(鎖定(ding)狀(zhuang)態(tai)則返(fan)回EBUSY)沒有其他(ta)動作。 2.互斥鎖屬性 互斥鎖(suo)(suo)(suo)(suo)的(de)屬性在創建鎖(suo)(suo)(suo)(suo)的(de)時候指定,在LinuxThreads實現中僅有一(yi)個鎖(suo)(suo)(suo)(suo)類(lei)型屬性,不通的(de)鎖(suo)(suo)(suo)(suo)類(lei)型試圖(tu)對一(yi)個已經被(bei)鎖(suo)(suo)(suo)(suo)定的(de)互斥鎖(suo)(suo)(suo)(suo)加鎖(suo)(suo)(suo)(suo)時表現不通。當前(glibc 2.2.3,linuxthreads0.9)有四個值可(ke)供選擇: *PTHREAD_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖(suo)(suo)。當(dang)一個線程加鎖(suo)(suo)以后,其余請求鎖(suo)(suo)的線程將形成一個等待隊列(lie),并(bing)在(zai)解(jie)鎖(suo)(suo)后按優先(xian)級獲(huo)得鎖(suo)(suo)。這種(zhong)鎖(suo)(suo)策略保(bao)證了資源分配的公平性。 *PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,允許同一(yi)個(ge)線程(cheng)(cheng)對(dui)同一(yi)個(ge)鎖成功獲得多次,并通過多次unlock解(jie)鎖。如(ru)果是不(bu)同線程(cheng)(cheng)請求,則(ze)在(zai)加鎖線程(cheng)(cheng)解(jie)鎖時重(zhong)新競爭(zheng)。 *PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,如果同一個線程請求(qiu)同一個鎖,則返(fan)回(hui)EDEADLK,否(fou)則與PTHREAD_MUTEX_TIMED_NP類型動(dong)作相(xiang)同。這(zhe)樣就保證當步允許多次加鎖 時不會出現簡(jian)單(dan)情況下(xia)的死鎖。 *PTHREAD_MUTEX_ADAPTIVE_NP,適(shi)應鎖,動作簡(jian)單的(de)鎖類型(xing),僅等(deng)待解鎖后重新競(jing)爭。 3.鎖操作 鎖(suo)(suo)(suo)(suo)操作主要包括加鎖(suo)(suo)(suo)(suo)pthread_mutex_lock()、解(jie)(jie)鎖(suo)(suo)(suo)(suo)pthread_mutex_unlock()和測(ce)試加鎖(suo)(suo)(suo)(suo)pthread_mutex_trylock()三個,不(bu)論哪(na)種類(lei)型(xing)的(de)鎖(suo)(suo)(suo)(suo),都不(bu)可能被兩個不(bu)同的(de)線程(cheng)時得(de)到,而必須等待解(jie)(jie)鎖(suo)(suo)(suo)(suo)。對于普通(tong)鎖(suo)(suo)(suo)(suo)和適應鎖(suo)(suo)(suo)(suo)類(lei)型(xing),解(jie)(jie)鎖(suo)(suo)(suo)(suo)者可以是同進(jin)程(cheng)內任(ren)何(he)線程(cheng);而檢錯鎖(suo)(suo)(suo)(suo)則必須由加鎖(suo)(suo)(suo)(suo)者解(jie)(jie)鎖(suo)(suo)(suo)(suo)才有效(xiao),否(fou)則EPERM;對于嵌套鎖(suo)(suo)(suo)(suo),文(wen)檔和實現要求(qiu)必須由加鎖(suo)(suo)(suo)(suo)者解(jie)(jie)鎖(suo)(suo)(suo)(suo),但(dan)試驗結果(guo)(guo)表明并沒有這種限制,這個不(bu)同目前還沒有得(de)到解(jie)(jie)釋(shi)。在同一進(jin)程(cheng)中的(de)線程(cheng),如(ru)果(guo)(guo)加鎖(suo)(suo)(suo)(suo)后沒有解(jie)(jie)鎖(suo)(suo)(suo)(suo),則任(ren)何(he)其他線程(cheng)都無法在獲(huo)得(de)鎖(suo)(suo)(suo)(suo)。 
	int pthread_mutex_lock(pthread_mutex_t *mutex); phread_mutex_trylock()語義與pthread_mutex_lock()類(lei)似,不同的(de)是在鎖已(yi)經被占(zhan)用時返回EBUSY而不是掛(gua)起(qi)等待。 四(si)、使用條件變量提高效率 如(ru)果線程正(zheng)在等待某(mou)個特定(ding)條件發生,它(ta)應該(gai)如(ru)何處理這(zhe)(zhe)種(zhong)(zhong)情況(kuang)?它(ta)可(ke)以重復對互斥對象鎖(suo)定(ding)和(he)解鎖(suo),每次(ci)都會檢查(cha)共享(xiang)數據結,以查(cha)找(zhao)某(mou)個值(zhi)。但這(zhe)(zhe)是(shi)在浪(lang)費時間和(he)資源,而且這(zhe)(zhe)種(zhong)(zhong)繁(fan)忙查(cha)詢的效率非常低。解決這(zhe)(zhe)個問題的佳方(fang)法(fa)是(shi)使用pthread_cond_wait()調(diao)用來等待特殊條件發生。 條(tiao)件(jian)(jian)變量(liang)(liang)是利用線(xian)程間共享的全局變量(liang)(liang)進行(xing)同步的一(yi)種機制,主要包括連(lian)個(ge)動作:一(yi)個(ge)線(xian)程等(deng)待(dai)"條(tiao)件(jian)(jian)變量(liang)(liang)的條(tiao)件(jian)(jian)成(cheng)立(li)"而掛起(qi);另(ling)一(yi)個(ge)線(xian)程使"條(tiao)件(jian)(jian)成(cheng)立(li)"(給出條(tiao)件(jian)(jian)成(cheng)立(li)信號)。為了防止競爭,條(tiao)件(jian)(jian)變量(liang)(liang)的使用總是和一(yi)個(ge)互斥鎖結合在一(yi)起(qi)。 1.創建和注銷 條件變量和(he)互斥鎖一(yi)樣,都有靜(jing)(jing)態(tai)(tai)、動(dong)態(tai)(tai)兩種創建方(fang)式,靜(jing)(jing)態(tai)(tai)方(fang)式使(shi)用PTHREAD_COND_INITIALIZER常量,如下: pthread_cond_t cond=PTHREAD_COND_INITIALIZER 動態方式(shi)調(diao)用pthread_cond_init()函(han)數(shu),API定義如(ru)下: int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr); 盡管(guan)POSIX標準(zhun)中為(wei)條件變量(liang)定義了(le)屬性,但在LinuxThreads中沒(mei)有實現,因此cond_attr值通常為(wei)NULL,且被忽(hu)略。 注(zhu)銷(xiao)一個條(tiao)件變量(liang)(liang)需(xu)要調用pthread_cond_destroy(),只(zhi)有在沒(mei)有線(xian)程在該條(tiao)件變量(liang)(liang)上等待(dai)的(de)時候才能注(zhu)銷(xiao)這個條(tiao)件變量(liang)(liang),否(fou)(fou)則返回EBUSY。因為Linux實現的(de)條(tiao)件變量(liang)(liang)沒(mei)有分(fen)配(pei)什么(me)資源,所(suo)以(yi)注(zhu)銷(xiao)動(dong)作(zuo)只(zhi)包括檢查是否(fou)(fou)有等待(dai)線(xian)程。API定下如(ru)下: int pthread_cond_destroy(pthread_cond_t *cond); 2.等待和激發 
	int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex) 等待條(tiao)件(jian)有(you)兩種方(fang)式:無條(tiao)件(jian)等待pthread_cond_wait()和計時等待pthread_cond_timedwait(),其(qi)中(zhong)計時等待如果在給定(ding)時刻前條(tiao)件(jian)沒有(you)滿足(zu),則返回(hui)ETIMEOUT,結束等待,其(qi)中(zhong)abstime以與time()系(xi)統調用相同意義的絕對時間形式出(chu)現,0表示格林時間1970年1月1日0時0分0秒(miao)。 無論哪種(zhong)等(deng)待(dai)方式,都必(bi)(bi)須和(he)一個互(hu)斥(chi)鎖配合,以防止多(duo)個線程(cheng)(cheng)同(tong)時(shi)請求pthread_cond_wait()(或(huo)pthread_cond_timedwait(),下同(tong))的競(jing)爭條件(jian)。mutex互(hu)斥(chi)鎖必(bi)(bi)須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或(huo)者適應(ying)鎖(PTHREAD_MUTEX_ADAPTIVE_NP),且在調用pthread_cond_wait()前必(bi)(bi)須給本線程(cheng)(cheng)加(jia)鎖(pthread_mutex_lock()),而在更新條件(jian)等(deng)待(dai)隊列以前,mutex保持鎖定(ding)狀態(tai),并(bing)在線程(cheng)(cheng)掛起(qi)進(jin)入(ru)等(deng)待(dai)前解鎖。在條件(jian)滿足從而離開pthread_cond_wait()之前,mutex將被重新加(jia)鎖,以與(yu)進(jin)入(ru)pthread_cond_wait()前的加(jia)鎖動作(zuo)對應(ying)。 激發條件有兩種形式,pthread_cond_signal()激活一個(ge)等待(dai)(dai)該條件的線(xian)程,存在多個(ge)等待(dai)(dai)線(xian)程時按(an)入隊順(shun)序激活其中一個(ge);而pthread_cond_broadcast()則激活所有等待(dai)(dai)線(xian)程。 
 相關資訊 發表評論 
 |