Linux下多線程的應(yīng)用
時(shí)間:2017-01-05作者:華清遠(yuǎn)見
一、創(chuàng)建線程 函數(shù)簡(jiǎn)介 phread_create是UNIX環(huán)境創(chuàng)建線程函數(shù) 頭文件 #include<pthread.h> 函數(shù)聲明
int pthread_create(pthread_t *restrict tidp 返回值 若成功則返回0,否則返回出錯(cuò)編號(hào) 返回成功時(shí),由tidp指向的內(nèi)存單元被設(shè)置為新創(chuàng)建線程的線程ID。attr參數(shù)用于制定各種不同的線程屬性。新創(chuàng)建的線程從start_rtn函數(shù)的地址開始運(yùn)行,該函數(shù)只有一個(gè)空指針參數(shù)arg,如果需要像start_rtn函數(shù)傳遞的參數(shù)不止一個(gè),那么需要把這些參數(shù)放到一個(gè)結(jié)構(gòu)體中,然后把這個(gè)結(jié)構(gòu)的地址作為arg的參數(shù)傳入。 linux下用c開發(fā)多線程程序,linux系統(tǒng)下的多線程遵循POSIX線程接口,稱為pthread。 參數(shù)
第一參數(shù)為指向線程標(biāo)識(shí)符的指針 另外,在編譯時(shí)注意加上-lpthread參數(shù),以調(diào)用靜態(tài)連接庫(kù)。因?yàn)閜thread并非linux系統(tǒng)的默認(rèn)庫(kù)。 二、pthread_join 函數(shù)pthread_join用來(lái)等待一個(gè)線程的結(jié)束。函數(shù)原型為: extern int phread_join (pthead_t __th,void **_thread_return); 第一個(gè)參數(shù)為被等待的線程標(biāo)識(shí)符。第二個(gè)參數(shù)為一個(gè)用戶定義的指針,它可以用來(lái)存儲(chǔ)被等待線程的返會(huì)值。這個(gè)函數(shù)是一個(gè)線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時(shí),被等待線程的資源被收回。如果執(zhí)行成功,將返回0,如果失敗則返回一個(gè)錯(cuò)誤號(hào)。 在linux中,默認(rèn)情況下是在一個(gè)線程被創(chuàng)建后,必須使用此函數(shù)對(duì)創(chuàng)建的線程進(jìn)行資源回收,但是可以設(shè)置Threads attributes來(lái)設(shè)置當(dāng)一個(gè)線程結(jié)束時(shí),直接回收此線程所占用的系統(tǒng)資源。 三、 互斥鎖pthread_mutex_t的使用 1.兩種方法創(chuàng)建互斥鎖,靜態(tài)方式和動(dòng)態(tài)方式。 POXIX定義了一個(gè)PTHREAD_MUTEX_INITIALIZER來(lái)靜態(tài)初始化互斥鎖,方法如下:phread_mutex_t mutex=PTHREAD_MUTEX_INITALIZER;在LinuxThreads實(shí)現(xiàn)中,pthread_mutex_t是一個(gè)結(jié)構(gòu),而PTHREAD_MUTEX_INITIALIZER則是一個(gè)結(jié)構(gòu)常量。 動(dòng)態(tài)方式是采用pthread_mutex_init()函數(shù)來(lái)初始化互斥鎖,API定義如下: int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr)其中mutexattr用于指定互斥屬性(見下),如果為NULL則使用缺省屬性。 pthread_mutex_destroy()用于注銷一個(gè)互斥鎖,API定義如下:int pthread_mutex_destory(pthread_mutex_t *mutex) 銷毀一個(gè)互斥鎖即意味著釋放它所占用的資源,且要求鎖當(dāng)前處于開發(fā)狀態(tài)。由于在linux中,互斥鎖并不占用任何資源,因此LinuxThreads中的pthread_mutex_destroy()除了檢查鎖狀態(tài)以外(鎖定狀態(tài)則返回EBUSY)沒有其他動(dòng)作。 2.互斥鎖屬性 互斥鎖的屬性在創(chuàng)建鎖的時(shí)候指定,在LinuxThreads實(shí)現(xiàn)中僅有一個(gè)鎖類型屬性,不通的鎖類型試圖對(duì)一個(gè)已經(jīng)被鎖定的互斥鎖加鎖時(shí)表現(xiàn)不通。當(dāng)前(glibc 2.2.3,linuxthreads0.9)有四個(gè)值可供選擇: *PTHREAD_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖。當(dāng)一個(gè)線程加鎖以后,其余請(qǐng)求鎖的線程將形成一個(gè)等待隊(duì)列,并在解鎖后按優(yōu)先級(jí)獲得鎖。這種鎖策略保證了資源分配的公平性。 *PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,允許同一個(gè)線程對(duì)同一個(gè)鎖成功獲得多次,并通過(guò)多次unlock解鎖。如果是不同線程請(qǐng)求,則在加鎖線程解鎖時(shí)重新競(jìng)爭(zhēng)。 *PTHREAD_MUTEX_ERRORCHECK_NP,檢錯(cuò)鎖,如果同一個(gè)線程請(qǐng)求同一個(gè)鎖,則返回EDEADLK,否則與PTHREAD_MUTEX_TIMED_NP類型動(dòng)作相同。這樣就保證當(dāng)步允許多次加鎖 時(shí)不會(huì)出現(xiàn)簡(jiǎn)單情況下的死鎖。 *PTHREAD_MUTEX_ADAPTIVE_NP,適應(yīng)鎖,動(dòng)作簡(jiǎn)單的鎖類型,僅等待解鎖后重新競(jìng)爭(zhēng)。 3.鎖操作 鎖操作主要包括加鎖pthread_mutex_lock()、解鎖pthread_mutex_unlock()和測(cè)試加鎖pthread_mutex_trylock()三個(gè),不論哪種類型的鎖,都不可能被兩個(gè)不同的線程時(shí)得到,而必須等待解鎖。對(duì)于普通鎖和適應(yīng)鎖類型,解鎖者可以是同進(jìn)程內(nèi)任何線程;而檢錯(cuò)鎖則必須由加鎖者解鎖才有效,否則EPERM;對(duì)于嵌套鎖,文檔和實(shí)現(xiàn)要求必須由加鎖者解鎖,但試驗(yàn)結(jié)果表明并沒有這種限制,這個(gè)不同目前還沒有得到解釋。在同一進(jìn)程中的線程,如果加鎖后沒有解鎖,則任何其他線程都無(wú)法在獲得鎖。
int pthread_mutex_lock(pthread_mutex_t *mutex); phread_mutex_trylock()語(yǔ)義與pthread_mutex_lock()類似,不同的是在鎖已經(jīng)被占用時(shí)返回EBUSY而不是掛起等待。 四、使用條件變量提高效率 如果線程正在等待某個(gè)特定條件發(fā)生,它應(yīng)該如何處理這種情況?它可以重復(fù)對(duì)互斥對(duì)象鎖定和解鎖,每次都會(huì)檢查共享數(shù)據(jù)結(jié),以查找某個(gè)值。但這是在浪費(fèi)時(shí)間和資源,而且這種繁忙查詢的效率非常低。解決這個(gè)問題的佳方法是使用pthread_cond_wait()調(diào)用來(lái)等待特殊條件發(fā)生。 條件變量是利用線程間共享的全局變量進(jìn)行同步的一種機(jī)制,主要包括連個(gè)動(dòng)作:一個(gè)線程等待"條件變量的條件成立"而掛起;另一個(gè)線程使"條件成立"(給出條件成立信號(hào))。為了防止競(jìng)爭(zhēng),條件變量的使用總是和一個(gè)互斥鎖結(jié)合在一起。 1.創(chuàng)建和注銷 條件變量和互斥鎖一樣,都有靜態(tài)、動(dòng)態(tài)兩種創(chuàng)建方式,靜態(tài)方式使用PTHREAD_COND_INITIALIZER常量,如下: pthread_cond_t cond=PTHREAD_COND_INITIALIZER 動(dòng)態(tài)方式調(diào)用pthread_cond_init()函數(shù),API定義如下: int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr); 盡管POSIX標(biāo)準(zhǔn)中為條件變量定義了屬性,但在LinuxThreads中沒有實(shí)現(xiàn),因此cond_attr值通常為NULL,且被忽略。 注銷一個(gè)條件變量需要調(diào)用pthread_cond_destroy(),只有在沒有線程在該條件變量上等待的時(shí)候才能注銷這個(gè)條件變量,否則返回EBUSY。因?yàn)長(zhǎng)inux實(shí)現(xiàn)的條件變量沒有分配什么資源,所以注銷動(dòng)作只包括檢查是否有等待線程。API定下如下: int pthread_cond_destroy(pthread_cond_t *cond); 2.等待和激發(fā)
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex) 等待條件有兩種方式:無(wú)條件等待pthread_cond_wait()和計(jì)時(shí)等待pthread_cond_timedwait(),其中計(jì)時(shí)等待如果在給定時(shí)刻前條件沒有滿足,則返回ETIMEOUT,結(jié)束等待,其中abstime以與time()系統(tǒng)調(diào)用相同意義的絕對(duì)時(shí)間形式出現(xiàn),0表示格林時(shí)間1970年1月1日0時(shí)0分0秒。 無(wú)論哪種等待方式,都必須和一個(gè)互斥鎖配合,以防止多個(gè)線程同時(shí)請(qǐng)求pthread_cond_wait()(或pthread_cond_timedwait(),下同)的競(jìng)爭(zhēng)條件。mutex互斥鎖必須是普通鎖(PTHREAD_MUTEX_TIMED_NP)或者適應(yīng)鎖(PTHREAD_MUTEX_ADAPTIVE_NP),且在調(diào)用pthread_cond_wait()前必須給本線程加鎖(pthread_mutex_lock()),而在更新條件等待隊(duì)列以前,mutex保持鎖定狀態(tài),并在線程掛起進(jìn)入等待前解鎖。在條件滿足從而離開pthread_cond_wait()之前,mutex將被重新加鎖,以與進(jìn)入pthread_cond_wait()前的加鎖動(dòng)作對(duì)應(yīng)。 激發(fā)條件有兩種形式,pthread_cond_signal()激活一個(gè)等待該條件的線程,存在多個(gè)等待線程時(shí)按入隊(duì)順序激活其中一個(gè);而pthread_cond_broadcast()則激活所有等待線程。
相關(guān)資訊
發(fā)表評(píng)論
|