前言:
通過linux的pthread庫, 相信大家對創建/銷毀線程肯定很熟悉, 不過對pthread_join是否知道的更多呢?
實驗:
先編寫一個常規的程序
#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; // *) 創建線程 pthread_create(&tid, NULL, thread_rountine, NULL); // *) 等待線程結束 pthread_join(tid, NULL); return 0; }
評注: 這是簡單的關於線程創建, 以及通過pthread_join阻塞等待子線程退出的例子
pthread_join是否真的只是為了執行順序, 等待子線程退出的一種機制? 難道就沒有其他作用了嗎?
答案是肯定的, 我們先來寫個程序, 做下對比:
#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; }
評注: 這邊我們去掉了(1)pthread_join, (2) pthread_detach
最終的程序輸出結果為:
error_msg => Resource temporarily unavailable
我們可以大膽地猜想進程的線程數有個限制, 那我們的程序究竟在那個環節出錯了? 疏忽什么導致線程資源沒被完全收回?
和Java開發多線程程序相比, 覺得搞java的人實在太幸福了.
在回到原問題, 如果我們添加(1)pthread_join, 或者(2)pthread_detach, 問題解決了.
我們查下man, 看看"專家"如何解說pthread_join
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).
評注: 如果沒有對joinable的線程, 作pthread_join, 會導致線程成為"zombie thread", 依舊會占據這個資源. 這也就不難理解了,為何明明都是短任務線程, 沒有加pthread_join, 主線程就不能再創建線程了. pthread_join其實作了部分線程銷毀的工作. 另一方面, 子線程能通過pthread_detach函數, 在線程自身退出時做好清理工作.
這邊有個疑惑:
在linux中, 如何限制進程的線程數? 線程數的上限由什么來限定?
后記:
真的是好久沒寫c++程序了, 也挺想念的, 不知何時還有機會做linux下c/c++開發, 還是never?