多線程編程要使用的函數(shù)

創(chuàng)建線程

int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_function)(void *),void *restrict arg)
//成功返回0,其他值則出錯(cuò)
// 第一個(gè)參數(shù)為指向線程標(biāo)識(shí)符的指針.第二個(gè)參數(shù)用來設(shè)置線程的屬性斋扰,第三個(gè)參數(shù)是線程運(yùn)行函數(shù)的起始位置,第四個(gè)參數(shù)是運(yùn)行函數(shù)的參數(shù)

extern int pthread_join __p(pthread_t __th,void ** __thread_return);
//第一個(gè)參數(shù)為被等待的線程標(biāo)識(shí)符,第二個(gè)參數(shù)為一個(gè)用戶定義的指針逆皮,它可以用來存儲(chǔ)被等待線程的返回值.
//這個(gè)函數(shù)是一個(gè)線程阻塞的函數(shù)帘饶,調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止,當(dāng)函數(shù)返回時(shí)答朋,被等待線程的資源被收回碗旅。如果執(zhí)行成功渡处,將返回0,如果失敗則返回一個(gè)錯(cuò)誤號(hào)祟辟。

C99新增restrict用于限定指針;該關(guān)鍵字用于告訴編譯器,所有修改該指針?biāo)赶虻膬?nèi)容的操作全部都是基于該指針的,即不存在其它進(jìn)行修改操作的途徑;這樣可以幫助編譯器進(jìn)行更好的代碼優(yōu)化.生成更有效率的匯編代碼.在gcc中使用C99標(biāo)準(zhǔn)要加上 -std=C99;
例如:void *memcpy( void * restrict dest ,const void * restrict src,sizi_t n) 這是一個(gè)很有用的內(nèi)存復(fù)制函數(shù)医瘫,由于兩個(gè)參數(shù)都加了restrict限定,所以兩塊區(qū)域不能重疊旧困,即 dest指針?biāo)傅膮^(qū)域醇份,不能讓別的指針來修改稼锅,即src的指針不能修改. 相對(duì)應(yīng)的別一個(gè)函數(shù) memmove(void *dest,const void * src,size_t)則可以重疊。

  • 與fork()調(diào)用創(chuàng)建一個(gè)進(jìn)程的方法不同,pthread_create()創(chuàng)建的線程并不具備和主線程(即調(diào)用pthread_create()的線程)同樣的執(zhí)行序列,而是使其運(yùn)行start_routine(arg)函數(shù)僚纷。thread返回創(chuàng)建的線程ID矩距,而 attr是創(chuàng)建線程時(shí)設(shè)置的線程屬性。pthread_create()的返回值表示線程創(chuàng)建是否成功怖竭。盡管arg是void *類型的變量锥债,但它同樣可以作為任意類型的參數(shù)傳給start_routine()函數(shù);同時(shí)痊臭,start_routine()可以返回一個(gè)void *類型的返回值赞弥,而這個(gè)返回值也可以是其他類型,并由pthread_join()獲取趣兄。
  • 為了設(shè)置attr屬性绽左,POSIX定義了一系列屬性設(shè)置函數(shù),包括pthread_attr_init()艇潭、pthread_attr_destroy()和與各個(gè)屬性相關(guān)的pthread_attr_get---/pthread_attr_set---函數(shù)拼窥。

線程取消

通常線程會(huì)在主體函數(shù)退出的時(shí)候自動(dòng)終止,但是也可以因?yàn)槭盏搅硗庖粋€(gè)線程發(fā)來的終止(取消)請(qǐng)求而強(qiáng)制終止.線程取消的方法是向目標(biāo)線程發(fā)送cancel信號(hào),但是如何處理cancel信號(hào)則是由目標(biāo)線程自己決定的,可以忽略,立即終止,或者是繼續(xù)運(yùn)行到cancelation-point(取消點(diǎn)),由不同的cancelation狀態(tài)決定.線程收到CANCEL信號(hào)的缺省狀態(tài)是運(yùn)行到取消點(diǎn)(pthread_create()創(chuàng)建線程的缺省狀態(tài)).
取消點(diǎn)包括以下一些函數(shù):pthread_join(),pthread_testcancel(),pthread_condition_wait(),pthread_cond_timewait(),sem_wait(),sigwait()等等函數(shù),以及read(),write()等會(huì)引起阻塞的系統(tǒng)調(diào)用都是取消點(diǎn).而其他pthread函數(shù)都不會(huì)引起Cancelation動(dòng)作。但是pthread_cancel的手 冊(cè)頁(yè)聲稱蹋凝,由于LinuxThread庫(kù)與C庫(kù)結(jié)合得不好鲁纠,因而目前C庫(kù)函數(shù)都不是Cancelation-point;但CANCEL信號(hào)會(huì)使線程從阻 塞的系統(tǒng)調(diào)用中退出鳍寂,并置EINTR錯(cuò)誤碼改含,因此可以在需要作為Cancelation-point的系統(tǒng)調(diào)用前后調(diào)用 pthread_testcancel(),從而達(dá)到POSIX標(biāo)準(zhǔn)所要求的目標(biāo)迄汛,即如下代碼段:

pthread_testcancel();
retcode = read(fd,buffer,length);
pthread_testcancel();
  • 若線程處于無(wú)限循環(huán),且沒有執(zhí)行到取消點(diǎn)的必然路徑,則線程無(wú)法由外部的其他線程取消請(qǐng)求而終止,因此在這樣的循環(huán)體的必經(jīng)路徑上應(yīng)該加入pthread_testcancel()調(diào)用.

  • 通過 int pthread_cancel(pthread_t tid);發(fā)送終止信號(hào)給thread線程,若成功則返回0,否則非0,成功發(fā)送并不意味著thread會(huì)終止.(那么檢查pthread_cancel的返回狀態(tài)不是沒有意義么???)

  • int pthread_setcancelstate(int state, int *oldstate):設(shè)置本線程對(duì)Cancel信號(hào)的反應(yīng)捍壤,state有兩種值:PTHREAD_CANCEL_ENABLE(缺省)PTHREAD_CANCEL_DISABLE鞍爱,分別表示收到信號(hào)后設(shè)為CANCLED狀態(tài)和忽略CANCEL信號(hào)繼續(xù)運(yùn)行鹃觉;old_state如果不為 NULL則存入原來的Cancel狀態(tài)以便恢復(fù)。

  • int pthread_setcanceltype(int type, int *oldtype)設(shè)置本線程取消動(dòng)作的執(zhí)行時(shí)機(jī)睹逃,type由兩種取值:PTHREAD_CANCEL_DEFFEREDPTHREAD_CANCEL_ASYCHRONOUS盗扇,僅當(dāng)Cancel狀態(tài)為Enable時(shí)有效,分別表示收到信號(hào)后繼續(xù)運(yùn)行至下一個(gè)取消點(diǎn)再退出和 立即執(zhí)行取消動(dòng)作(退出)沉填;oldtype如果不為NULL則存入運(yùn)來的取消動(dòng)作類型值疗隶。

  • void pthread_testcancel(void)檢查本線程是否處于Canceld狀態(tài),如果是翼闹,則進(jìn)行取消動(dòng)作斑鼻,否則直接返回。


互斥鎖

pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

  • pthread_mutex_t 是posix下抽象出的一個(gè)鎖類型的結(jié)構(gòu):pthread_mutex_t.通過對(duì)該結(jié)構(gòu)的訪問.顧名思義橄碾,加鎖以后卵沉,別人就無(wú)法打開,只有當(dāng)鎖沒有關(guān)閉的時(shí)候才可以訪問資源.使用互斥鎖可以讓線程按順序執(zhí)行.通常法牲,互斥鎖通過確保一次只有一個(gè)線程執(zhí)行代碼的臨界段來同步多個(gè)線程.互斥鎖還可以保護(hù)單線程代碼.要更改缺省的互斥鎖屬性史汗,可以對(duì)屬性對(duì)象進(jìn)行聲明和初始化。通常拒垃,互斥鎖屬性會(huì)設(shè)置在應(yīng)用程序開頭的某個(gè)位置停撞,以便可以快速查找和輕松修改。
  • pthread_mutex_init()函數(shù)是以動(dòng)態(tài)方式創(chuàng)建互斥鎖的悼瓮,參數(shù)attr指定了新建互斥鎖的屬性戈毒。如果參數(shù)attr為NULL,則使用默認(rèn)的互斥鎖屬性横堡,默認(rèn)屬性為快速互斥鎖 埋市。互斥鎖的屬性在創(chuàng)建鎖的時(shí)候指定命贴,在LinuxThreads實(shí)現(xiàn)中僅有一個(gè)鎖類型屬性道宅,不同的鎖類型在試圖對(duì)一個(gè)已經(jīng)被鎖定的互斥鎖加鎖時(shí)表現(xiàn)不同。函數(shù)成功完成之后會(huì)返回0胸蛛,其他的任何值表示出現(xiàn)錯(cuò)誤.執(zhí)行成功后污茵,互斥鎖被初始化為鎖住的狀態(tài).

互斥鎖的屬性:

  1. PTHREAD_MUTEX_TIMED_NP,這是缺省值葬项,也就是普通鎖泞当。當(dāng)一個(gè)線程加鎖以后,其余請(qǐng)求鎖的線程將形成一個(gè)等待隊(duì)列民珍,并在解鎖后按優(yōu)先級(jí)獲得鎖襟士。這種鎖策略保證了資源分配的公平性。
  2. PTHREAD_MUTEX_RECURSIVE_NP嚷量,嵌套鎖敌蜂,允許同一個(gè)線程對(duì)同一個(gè)鎖成功獲得多次,并通過多次unlock解鎖津肛。如果是不同線程請(qǐng)求章喉,則在加鎖線程解鎖時(shí)重新競(jìng)爭(zhēng)。
  3. PTHREAD_MUTEX_ERRORCHECK_NP身坐,檢錯(cuò)鎖崔涂,如果同一個(gè)線程請(qǐng)求同一個(gè)鎖,則返回EDEADLK策幼,否則與PTHREAD_MUTEX_TIMED_NP類型動(dòng)作相同狈涮。這樣就保證當(dāng)不允許多次加鎖時(shí)不會(huì)出現(xiàn)最簡(jiǎn)單情況下的死鎖。
  4. PTHREAD_MUTEX_ADAPTIVE_NP涯鲁,適應(yīng)鎖巷查,動(dòng)作最簡(jiǎn)單的鎖類型有序,僅等待解鎖后重新競(jìng)爭(zhēng)。
鎖的一些操作
  1. int pthread_mutxe_lock(pthread_mutex_t *mutex)
  2. int phread_mutex_unlock(pthread_mutex_t *mutex)
  3. int pthread_mutex_trylock(pthread_mutex_t *mutex)

pthread_mutex_trylock()語(yǔ)義與pthread_mutex_lock()類似岛请,不同的是在鎖已經(jīng)被占據(jù)時(shí)返回EBUSY而不是掛起等待旭寿。

死鎖

死鎖主要發(fā)生在有多個(gè)依賴鎖存在時(shí), 會(huì)在一個(gè)線程試圖以與另一個(gè)線程相反順序鎖住互斥量時(shí)發(fā)生. 如何避免死鎖是使用互斥量應(yīng)該格外注意的東西〕绨埽總體來講, 有幾個(gè)不成文的基本原則:

  1. 對(duì)共享資源操作前一定要獲得鎖盅称。
  2. 完成操作以后一定要釋放鎖。
  3. 盡量短時(shí)間地占用鎖后室。
  4. 如果有多鎖, 如獲得順序是ABC連環(huán)扣, 釋放順序也應(yīng)該是ABC缩膝。
  5. 線程錯(cuò)誤返回時(shí)應(yīng)該釋放它所獲得的鎖。

條件變量

#include <pthread.h>
pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *attr);
//成功返回0岸霹,其他的值表示錯(cuò)誤

不能由多個(gè)線程同時(shí)初始化一個(gè)條件變量疾层。當(dāng)需要重新初始化或釋放一個(gè)條件變量時(shí),應(yīng)用程序必須保證這個(gè)條件變量未被使用贡避。

int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mutex);
//返回0表示成功云芦,其他值表示失敗

該函數(shù)將解鎖mutex參數(shù)指向的互斥鎖,并使當(dāng)前線程阻塞在cv參數(shù)指向的條件變量上贸桶。被阻塞的線程可以被pthread_cond_signal函數(shù)舅逸,pthread_cond_broadcast函數(shù)喚醒,也可能在被信號(hào)中斷后被喚醒皇筛。pthread_cond_wait函數(shù)的返回并不意味著條件的值一定發(fā)生了變化琉历,必須重新檢查條件的值。pthread_cond_wait函數(shù)返回時(shí)水醋,相應(yīng)的互斥鎖將被當(dāng)前線程鎖定旗笔,即使是函數(shù)出錯(cuò)返回。一般一個(gè)條件表達(dá)式都是在一個(gè)互斥鎖的保護(hù)下被檢查拄踪。當(dāng)條件表達(dá)式未被滿足時(shí)蝇恶,線程將仍然阻塞在這個(gè)條件變量上。當(dāng)另一個(gè)線程改變了條件的值并向條件變量發(fā)出信號(hào)時(shí)惶桐,等待在這個(gè)條件變量上的一個(gè)線程或所有線程被喚醒撮弧,接著都試圖再次占有相應(yīng)的互斥鎖。


pthread_cleanup_push()和pthread_cleanup_pop()的目的和作用

例如一個(gè)線程thread1:

pthread_mutex_lock(&mutex);
//一些會(huì)阻塞程序運(yùn)行的調(diào)用姚糊,比如套接字的accept贿衍,等待客戶連接
sock = accept(......);            //這里是隨便找的一個(gè)可以阻塞的接口
pthread_mutex_unlock(&mutex);

上例中若線程1執(zhí)行了accept(),線程會(huì)阻塞(也就是等在那里,有客戶端連接的時(shí)候才返回救恨,或則出現(xiàn)其他故障)贸辈,線程等待中......
這時(shí)候線程2發(fā)現(xiàn)線程1等了很久,不賴煩了肠槽,他想關(guān)掉線程1擎淤,于是調(diào)用pthread_cancel()或者類似函數(shù)奢啥,請(qǐng)求線程1立即退出。這時(shí)候線程1仍然在accept等待中嘴拢,當(dāng)它收到線程2的cancel信號(hào)后桩盲,就會(huì)從accept中退出,然后終止線程炊汤,注意這個(gè)時(shí)候線程1還沒有執(zhí)行:pthread_mutex_unlock(&mutex);也就是說鎖資源沒有釋放,這回造成其他線程的死鎖問題弊攘。
所以必須在線程接收到cancel后用一種方法來保證異常退出(也就是線程沒達(dá)到終點(diǎn))時(shí)可以做清理工作(主要是解鎖方面)抢腐,pthread_cleanup_pushpthread_cleanup_pop就是用來做這樣的工作的。

pthread_cleanup_push(some_clean_func,...)
pthread_mutex_lock(&mutex);
//一些會(huì)阻塞程序運(yùn)行的調(diào)用襟交,比如套接字的accept迈倍,等待客戶連接
sock = accept(......);            //這里是隨便找的一個(gè)可以阻塞的接口
pthread_mutex_unlock(&mutex);
pthread_cleanup_pop(0);
return NULL;

上面的代碼,如果accept被cancel后線程退出捣域,會(huì)自動(dòng)調(diào)用some_clean_func函數(shù)啼染,在這個(gè)函數(shù)中你可以釋放鎖資源。如果accept沒有被cancel焕梅,那么線程繼續(xù)執(zhí)行迹鹅,當(dāng)pthread_mutex_unlock(&mutex);表示線程自己正確的釋放資源了,而執(zhí)行pthread_cleanup_pop(0);也就是取消掉前面的some_clean_func函數(shù)贞言。接著return線程就正確的結(jié)束了斜棚。
push進(jìn)去的函數(shù)可能在以下三個(gè)時(shí)機(jī)執(zhí)行:

  1. 顯示的調(diào)用pthread_exit();
  2. 在cancel點(diǎn)線程被cancel。
  3. pthread_cleanup_pop()的參數(shù)不為0時(shí)该窗。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末弟蚀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子酗失,更是在濱河造成了極大的恐慌义钉,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件规肴,死亡現(xiàn)場(chǎng)離奇詭異捶闸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拖刃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門鉴嗤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人序调,你說我怎么就攤上這事醉锅。” “怎么了发绢?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵硬耍,是天一觀的道長(zhǎng)垄琐。 經(jīng)常有香客問我,道長(zhǎng)经柴,這世上最難降的妖魔是什么狸窘? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮坯认,結(jié)果婚禮上翻擒,老公的妹妹穿的比我還像新娘。我一直安慰自己牛哺,他們只是感情好陋气,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著引润,像睡著了一般巩趁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淳附,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天议慰,我揣著相機(jī)與錄音,去河邊找鬼奴曙。 笑死别凹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洽糟。 我是一名探鬼主播番川,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼脊框!你這毒婦竟也來了颁督?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤浇雹,失蹤者是張志新(化名)和其女友劉穎沉御,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體昭灵,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吠裆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了烂完。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片试疙。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抠蚣,靈堂內(nèi)的尸體忽然破棺而出祝旷,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布怀跛,位于F島的核電站距贷,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏吻谋。R本人自食惡果不足惜忠蝗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漓拾。 院中可真熱鬧阁最,春花似錦、人聲如沸骇两。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脯颜。三九已至哟旗,卻和暖如春贩据,著一層夾襖步出監(jiān)牢的瞬間栋操,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工饱亮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留矾芙,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓近上,卻偏偏與公主長(zhǎng)得像剔宪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壹无,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

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

  • 轉(zhuǎn)自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay閱讀 1,619評(píng)論 0 52
  • 一葱绒、線程的創(chuàng)建和調(diào)度 1.線程是程序執(zhí)行的某一條指令流的映像。 為了進(jìn)一步減少處理機(jī)制的空轉(zhuǎn)時(shí)間斗锭,支持多處理器及減...
    穹藍(lán)奧義閱讀 1,115評(píng)論 2 5
  • 線程基礎(chǔ) 線程是進(jìn)程的一個(gè)執(zhí)行單元地淀,執(zhí)行一段程序片段,線程共享全局變量岖是;線程的查看可以使用命令或者文件來進(jìn)行查看帮毁;...
    秋風(fēng)弄影閱讀 740評(píng)論 0 0
  • iOS 多線程系列 -- 基礎(chǔ)概述iOS 多線程系列 -- pthreadiOS 多線程系列 -- NSThrea...
    shannoon閱讀 2,643評(píng)論 1 8
  • 線程 在linux內(nèi)核那一部分我們知道,線程其實(shí)就是一種特殊的進(jìn)程豺撑,只是他們共享進(jìn)程的文件和內(nèi)存等資源烈疚,無(wú)論如何對(duì)...
    大雄good閱讀 668評(píng)論 0 2