最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

簡單了解C語言中主線程退出對(duì)子線程的影響

 更新時(shí)間:2019年12月17日 08:58:58   作者:Less is more  
這篇文章主要介紹了簡單了解C語言中主線程退出對(duì)子線程的影響,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

這篇文章主要介紹了簡單了解C語言中主線程退出對(duì)子線程的影響,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下

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

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

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

主線程先退出

先來看一個(gè)主線程先退出的例子:

#include <pthread.h>
#include <unistd.h>

#include <stdio.h>

void* func(void* arg)
{
  pthread_t main_tid = *static_cast<pthread_t*>(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;
}

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

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

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

主線程隨進(jìn)程一起退出

之前看到一些人說如果主線程先退出了,子線程也會(huì)跟著退出,其實(shí)他們混淆了線程退出和進(jìn)程退出的概念。下面這個(gè)例子代表了他們的觀點(diǎ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;
}

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

按照他們的邏輯,你看,因?yàn)橹骶€程在打印完「main exit」后退出了,然后子線程也跟著退出了,所以隨后就沒有子線程的打印了。

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

Linux線程模型

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

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

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

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

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

如果信號(hào)的默認(rèn)處理動(dòng)作是終止該進(jìn)程,那么把信號(hào)傳遞給某個(gè)線程仍然會(huì)殺掉整個(gè)進(jìn)程。

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

另外系統(tǒng)調(diào)用syscall(SYS_gettid)獲取的線程號(hào)與pthread_self獲取的線程號(hào)是不同的,pthread_self獲取的線程號(hào)僅僅在線程所依賴的進(jìn)程內(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)識(shí)線程ID的線程號(hào)只能通過系統(tǒng)調(diào)用syscall(SYS_gettid)獲取。

以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++淺析構(gòu)造函數(shù)的特性

    C++淺析構(gòu)造函數(shù)的特性

    構(gòu)造函數(shù)主要作用在于創(chuàng)建對(duì)象時(shí)為對(duì)象的成員屬性賦值,構(gòu)造函數(shù)由編譯器自動(dòng)調(diào)用,無須手動(dòng)調(diào)用;析構(gòu)函數(shù)主要作用在于對(duì)象銷毀前系統(tǒng)自動(dòng)調(diào)用,執(zhí)行一 些清理工作
    2022-07-07
  • C語言經(jīng)典順序表真題演練講解

    C語言經(jīng)典順序表真題演練講解

    程序中經(jīng)常需要將一組數(shù)據(jù)元素作為整體管理和使用,需要?jiǎng)?chuàng)建這種元素組,用變量記錄它們,傳進(jìn)傳出函數(shù)等。一組數(shù)據(jù)中包含的元素個(gè)數(shù)可能發(fā)生變化,順序表則是將元素順序地存放在一塊連續(xù)的存儲(chǔ)區(qū)里,元素間的順序關(guān)系由它們的存儲(chǔ)順序自然表示
    2022-04-04
  • c++中虛函數(shù)的實(shí)現(xiàn)詳解

    c++中虛函數(shù)的實(shí)現(xiàn)詳解

    眾所周知探索c++對(duì)象內(nèi)部的實(shí)現(xiàn)是一件非常有趣的事情,虛函數(shù)在c++中的實(shí)現(xiàn)機(jī)制就是用虛表和虛指針,但是具體是怎樣的呢?下面這篇文章就來給大家實(shí)際檢驗(yàn)一下 Visual Studio 2013 編譯器在無優(yōu)化條件下,虛函數(shù)的實(shí)現(xiàn)。有需要的朋友們可以參考借鑒,下面來一起看看吧。
    2016-12-12
  • C++ 讀寫文件安全又簡潔的簡單實(shí)例

    C++ 讀寫文件安全又簡潔的簡單實(shí)例

    這篇文章主要介紹了C++ 讀寫文件安全又簡潔的簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 基于C語言中野指針的深入解析

    基于C語言中野指針的深入解析

    “野指針”不是NULL指針,是指向“垃圾”內(nèi)存的指針。人們一般不會(huì)錯(cuò)用NULL指針,因?yàn)橛胕f語句很容易判斷。但是“野指針”是很危險(xiǎn)的,if語句對(duì)它不起作用
    2013-07-07
  • C++實(shí)現(xiàn)LeetCode(兩個(gè)有序數(shù)組的中位數(shù))

    C++實(shí)現(xiàn)LeetCode(兩個(gè)有序數(shù)組的中位數(shù))

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(兩個(gè)有序數(shù)組的中位數(shù)),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 基于Qt播放器的實(shí)現(xiàn)詳解(支持Rgb,YUV格式)

    基于Qt播放器的實(shí)現(xiàn)詳解(支持Rgb,YUV格式)

    這篇文章主要為大家詳細(xì)介紹了如何利用Qt實(shí)現(xiàn)簡易的播放器,可以支持支持Rgb,YUV格式。文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下
    2022-12-12
  • C語言安全編碼數(shù)組記法的一致性

    C語言安全編碼數(shù)組記法的一致性

    這篇文章主要介紹了C語言安全編碼數(shù)組記法的一致性,需要的朋友可以參考下
    2014-07-07
  • C/C++自主分配出現(xiàn)double free or corruption問題解決

    C/C++自主分配出現(xiàn)double free or corruption問題解決

    這篇文章主要為大家介紹了C/C++出現(xiàn)double free or corruption問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-04-04
  • 模擬鼠標(biāo)事件的實(shí)現(xiàn)思路及代碼

    模擬鼠標(biāo)事件的實(shí)現(xiàn)思路及代碼

    這篇文章主要介紹了模擬鼠標(biāo)事件的實(shí)現(xiàn)思路及代碼,有需要的朋友可以參考一下
    2013-12-12

最新評(píng)論

灵璧县| 渭源县| 炉霍县| 鲜城| 城步| 巴林左旗| 双鸭山市| 敖汉旗| 观塘区| 正宁县| 莱芜市| 三门县| 山东省| 肇东市| 六枝特区| 广德县| 文化| 富顺县| 乌审旗| 高要市| 安丘市| 芮城县| 安化县| 二手房| 明溪县| 互助| 樟树市| 厦门市| 金堂县| 邮箱| 龙岩市| 益阳市| 昭苏县| 石狮市| 潜江市| 陵水| 满洲里市| 思茅市| 高淳县| 济阳县| 利川市|