pthread_join和pthread_detach详解
??? 默認(rèn)情況下,線程被創(chuàng)建成可結(jié)合的。為了避免存儲(chǔ)器泄漏,每個(gè)可結(jié)合線程都應(yīng)該要么被顯示地回收,即調(diào)用pthread_join;要么通過(guò)調(diào)用pthread_detach函數(shù)被分離。
[cpp]
int pthread_join(pthread_t tid, void**thread_return);?
???????????????????????????????? 若成功則返回0,若出錯(cuò)則為非零。?
int pthread_join(pthread_t tid, void**thread_return);
???????????????????????????????? 若成功則返回0,若出錯(cuò)則為非零。??? 線程通過(guò)調(diào)用pthread_join函數(shù)等待其他線程終止。pthread_join函數(shù)分阻塞,直到線程tid終止,將線程例程返回的(void*)指針賦值為thread_return指向的位置,然后回收已終止線程占用的所有存儲(chǔ)器資源。[cpp] view plaincopyprint?int pthread_detach(pthread_t tid);?
???????????????????????????????? 若成功則返回0,若出錯(cuò)則為非零。?
int pthread_detach(pthread_t tid);
???????????????????????????????? 若成功則返回0,若出錯(cuò)則為非零。
??? pthread_detach用于分離可結(jié)合線程tid。線程能夠通過(guò)以pthread_self()為參數(shù)的pthread_detach調(diào)用來(lái)分離它們自己。
??? 如果一個(gè)可結(jié)合線程結(jié)束運(yùn)行但沒有被join,則它的狀態(tài)類似于進(jìn)程中的Zombie Process,即還有一部分資源沒有被回收,所以創(chuàng)建線程者應(yīng)該調(diào)用pthread_join來(lái)等待線程運(yùn)行結(jié)束,并可得到線程的退出代碼,回收其資源。
??? 由于調(diào)用pthread_join后,如果該線程沒有運(yùn)行結(jié)束,調(diào)用者會(huì)被阻塞,在有些情況下我們并不希望如此。例如,在Web服務(wù)器中當(dāng)主線程為每個(gè)新來(lái)的連接請(qǐng)求創(chuàng)建一個(gè)子線程進(jìn)行處理的時(shí)候,主線程并不希望因?yàn)檎{(diào)用pthread_join而阻塞(因?yàn)檫€要繼續(xù)處理之后到來(lái)的連接請(qǐng)求),這時(shí)可以在子線程中加入代碼
??? pthread_detach(pthread_self())
或者父線程調(diào)用
??? pthread_detach(thread_id)(非阻塞,可立即返回)
這將該子線程的狀態(tài)設(shè)置為分離的(detached),如此一來(lái),該線程運(yùn)行結(jié)束后會(huì)自動(dòng)釋放所有資源。
通過(guò)linux的pthread庫(kù), 相信大家對(duì)創(chuàng)建/銷毀線程肯定很熟悉, 不過(guò)對(duì)pthread_join是否知道的更多呢?
先編寫一個(gè)常規(guī)的程序
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #include <pthread.h> #include <stdio.h> #include <string.h> void *thread_rountine(void * /*args*/) { printf("thread %lu work\n", pthread_self()); } int main() { pthread_t tid; // *) 創(chuàng)建線程 pthread_create(&tid, NULL, thread_rountine, NULL);??? // *) 等待線程結(jié)束 pthread_join(tid, NULL); return 0; } |
評(píng)注: 這是簡(jiǎn)單的關(guān)于線程創(chuàng)建, 以及通過(guò)pthread_join阻塞等待子線程退出的例子
pthread_join是否真的只是為了執(zhí)行順序, 等待子線程退出的一種機(jī)制? 難道就沒有其他作用了嗎?
答案是肯定的, 我們先來(lái)寫個(gè)程序, 做下對(duì)比:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <sys/time.h> #include <sys/resource.h> #include <pthread.h> #include <stdio.h> #include <string.h> void *thread_rountine(void * /*args*/) { //pthread_detach(pthread_self());? ==> (2) } int main() { rlimit rl; getrlimit(RLIMIT_NPROC, &rl); for ( int i = 0; i < rl.rlim_cur; i++ ) { pthread_t tid; int ret = pthread_create(&tid, NULL, thread_rountine, NULL); if ( ret != 0 ) { printf("error_msg => %s\n", strerror(ret)); break; } // pthread_join(tid, NULL);? ==> (1) } return 0; } |
評(píng)注: 這邊我們?nèi)サ袅?1)pthread_join, (2) pthread_detach
最終的程序輸出結(jié)果為:
| 1 | error_msg => Resource temporarily unavailable |
我們可以大膽地猜想進(jìn)程的線程數(shù)有個(gè)限制, 那我們的程序究竟在那個(gè)環(huán)節(jié)出錯(cuò)了? 疏忽什么導(dǎo)致線程資源沒被完全收回?
和Java開發(fā)多線程程序相比, 覺得搞java的人實(shí)在太幸福了.
在回到原問(wèn)題, 如果我們添加(1)pthread_join, 或者(2)pthread_detach, 問(wèn)題解決了.
我們查下man, 看看"專家"如何解說(shuō)pthread_join
| 1 | Failure to join with a thread that is joinable (i.e., one that is not detached), produces a "zombie thread". Avoid doing this, since each zombie thread consumes some system resources, and when enough zombie threads have accumulated, it will no longer be possible to create new threads (or processes). |
評(píng)注: 如果沒有對(duì)joinable的線程, 作pthread_join, 會(huì)導(dǎo)致線程成為"zombie thread", 依舊會(huì)占據(jù)這個(gè)資源. 這也就不難理解了,為何明明都是短任務(wù)線程, 沒有加pthread_join, 主線程就不能再創(chuàng)建線程了. pthread_join其實(shí)作了部分線程銷毀的工作. 另一方面, 子線程能通過(guò)pthread_detach函數(shù), 在線程自身退出時(shí)做好清理工作.
總結(jié)
以上是生活随笔為你收集整理的pthread_join和pthread_detach详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 详解/etc/profile、/etc/
- 下一篇: Linux下profile和bashrc