真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

C語言中主線程退出對子線程的影響

本篇內(nèi)容主要講解“C語言中主線程退出對子線程的影響”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“C語言中主線程退出對子線程的影響”吧!

創(chuàng)新互聯(lián)是專業(yè)的元寶山網(wǎng)站建設(shè)公司,元寶山接單;提供網(wǎng)站制作、成都網(wǎng)站設(shè)計,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進行元寶山網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

對于程序來說,如果主進程在子進程還未結(jié)束時就已經(jīng)退出,那么Linux內(nèi)核會將子進程的父進程ID改為1(也就是init進程),當(dāng)子進程結(jié)束后會由init進程來回收該子進程。

那如果是把進程換成線程的話,會怎么樣呢?假設(shè)主線程在子線程結(jié)束前就已經(jīng)退出,子線程會發(fā)生什么?

在一些論壇上看到許多人說子線程也會跟著退出,其實這是錯誤的,原因在于他們混淆了線程退出和進程退出概念。實際的答案是主線程退出后子線程的狀態(tài)依賴于它所在的進程,如果進程沒有退出的話子線程依然正常運轉(zhuǎn)。如果進程退出了,那么它所有的線程都會退出,所以子線程也就退出了。

主線程先退出

先來看一個主線程先退出的例子:

#include #include #include void* func(void* arg){  pthread_t main_tid = *static_cast(arg);  pthread_cancel(main_tid);  while (true)  {    //printf("child loops\n");  }  return NULL;}int main(int argc, char* argv[]){  pthread_t main_tid = pthread_self();  pthread_t tid = 0;  pthread_create(&tid, NULL, func, &main_tid);  while (true)  {    printf("main loops\n");  }  sleep(1);  printf("main exit\n");  return 0;}

把主線程的線程號傳給子線程,在子線程中通過pthread_cancel終止主線程使其退出。運行程序,可以發(fā)現(xiàn)在打印了一定數(shù)量的「main loops」之后程序就掛起了,但卻沒有退出。

主線程因為被子線程終止了,所有沒有看到「main exit」的打印。子線程終止了主線程后進入了死循環(huán)while中,所以程序看起來像掛起了。如果我們讓子進程while循環(huán)中的打印語句生效再運行就可以發(fā)現(xiàn)程序會一直打印「child loops」字樣。

主線程被子線程終止了,但他們所依賴的進程并沒有退出,所以子線程依然正常運轉(zhuǎn)。

主線程隨進程一起退出

之前看到一些人說如果主線程先退出了,子線程也會跟著退出,其實他們混淆了線程退出和進程退出的概念。下面這個例子代表了他們的觀點:

void* func(void* arg){  while (true)  {    printf("child loops\n");  }  return NULL;}int main(int argc, char* argv[]){  pthread_t main_tid = pthread_self();  pthread_t tid = 0;  pthread_create(&tid, NULL, func, &main_tid);  sleep(1);  printf("main exit\n");  return 0;}

運行上面的代碼,會發(fā)現(xiàn)程序在打印一定數(shù)量的「child loops」和一句「main exit」之后退出,并且在退出之前的最后一句打印是「main exit」。

按照他們的邏輯,你看,因為主線程在打印完「main exit」后退出了,然后子線程也跟著退出了,所以隨后就沒有子線程的打印了。

但其實這里是混淆了進程退出和線程退出的概念了。實際的情況是主線程中的main函數(shù)執(zhí)行完ruturn后彈棧,然后調(diào)用glibc庫函數(shù)exit,exit進行相關(guān)清理工作后調(diào)用_exit系統(tǒng)調(diào)用退出該進程。所以,這種情況實際上是因為進程運行完畢退出導(dǎo)致所有的線程也都跟著退出了,并非是因為主線程的退出導(dǎo)致子線程也退出。

Linux線程模型

實際上,posix線程和一般的進程不同,在概念上沒有主線程和子線程之分(雖然在實際實現(xiàn)上還是有一些區(qū)分),如果仔細觀察apue或者unp等書會發(fā)現(xiàn)基本看不到「主線程」或者「子線程」等詞語,在csapp中甚至都是用「對等線程」一詞來描述線程間的關(guān)系。

在Linux 2.6以后的posix線程都是由用戶態(tài)的pthread庫來實現(xiàn)的。在使用pthread庫以后,在用戶視角看來,每一個tast_struct就對應(yīng)一個線程(tast_struct原本是內(nèi)核對應(yīng)一個進程的結(jié)構(gòu)),而一組線程以及他們所共同引用的一組資源就是進程。從Linux 2.6開始,內(nèi)核有了線程組的概念,tast_struct結(jié)構(gòu)中增加了一個tgid(thread group id)字段。getpid(獲取進程號)通過系統(tǒng)調(diào)用返回的也是tast_struct中的tgid,所以tgid其實就是進程號。而tast_struct中的線程號pid字段則由系統(tǒng)調(diào)用syscall(SYS_gettid)來獲取。

當(dāng)線程收到一個kill致命信號時,內(nèi)核會將處理動作施加到整個線程組上。為了應(yīng)付「發(fā)送給進程的信號」和「發(fā)送給線程的信號」,tast_struct里面維護了兩套signal_pending,一套是線程組共用的,一套是線程獨有的。通過kill發(fā)送的致命信號被放在線程組共享的signal_pending中,可以任意由一個線程來處理。而通過pthread_kill發(fā)送的信號被放在線程獨有的signal_pending中,只能由本線程來處理。

關(guān)于線程與信號,apue有這么幾句:

每個線程都有自己的信號屏蔽字,但是信號的處理是進程中所有線程共享的。這意味著盡管單個線程可以阻止某些信號,但當(dāng)線程修改了與某個信號相關(guān)的處理行為以后,所有的線程都必須共享這個處理行為的改變。這樣如果一個線程選擇忽略某個信號,而其他的線程可以恢復(fù)信號的默認處理行為,或者是為信號設(shè)置一個新的處理程序,從而可以撤銷上述線程的信號選擇。

如果信號的默認處理動作是終止該進程,那么把信號傳遞給某個線程仍然會殺掉整個進程。

例如一個程序a.out創(chuàng)建了一個子線程,假設(shè)主線程的線程號為9601,子線程的線程號為9602(它們的tgid都是9601),因為默認沒有設(shè)置信號處理程序,所以如果運行命令kill 9602的話,是可以把9601和9602這個兩個線程一起殺死的。如果不知道Linux線程背后的故事,可能就會覺得遇到靈異事件了。

另外系統(tǒng)調(diào)用syscall(SYS_gettid)獲取的線程號與pthread_self獲取的線程號是不同的,pthread_self獲取的線程號僅僅在線程所依賴的進程內(nèi)部唯一,在pthread_self的man page中有這樣一段話:

Thread IDs are guaranteed to be unique only within a process. A thread ID may be reused after a terminated thread has been joined, or a detached thread has terminated.

所以在內(nèi)核中唯一標(biāo)識線程ID的線程號只能通過系統(tǒng)調(diào)用syscall(SYS_gettid)獲取。

到此,相信大家對“C語言中主線程退出對子線程的影響”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


名稱欄目:C語言中主線程退出對子線程的影響
網(wǎng)頁URL:http://weahome.cn/article/ippjpg.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部