<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          有兩個這樣的進程:僵尸進程&孤兒進程,藍瘦香菇

          共 3231字,需瀏覽 7分鐘

           ·

          2020-08-05 03:22

          程序員的成長之路
          互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
          關(guān)注


          閱讀本文大概需要 5.8 分鐘。

          來自https://juejin.im/post/5f20fbeae51d45348675fa78

          那時剛寫公眾號,當時記錄的學(xué)習(xí)筆記,現(xiàn)在看來,之前記錄的有一個錯誤的地方,當時也沒察覺到。
          寫錯了就要改嘛,程序員也不能怕錯~
          不知道大家看自己幾年前的做事情,有的時候有沒有一種感覺,這是我做的嗎???
          好吧,有點嫌棄當時的自己~
          直接進入正題吧,父子進程之間到底有啥關(guān)系?

          進程

          先來說下什么是進程:
          來看下百度是怎么說的:
          光看說的不夠形象,在windows系統(tǒng)中,它長這樣:
          在Mac系統(tǒng)中,它長這樣:
          Linux中是這樣的:(有點長截圖一部分好了)
          [root@iz2ze76ybn73dvwmdij06zz?~]#?ps?-ef
          UID????????PID??PPID??C?STIME?TTY??????????TIME?CMD
          root?????????1?????0??0?5月20?????????00:00:33?/usr/lib/systemd/systemd?--system?--deserialize?21
          root?????????2?????0??0?5月20?????????00:00:00?[kthreadd]
          root?????????3?????2??0?5月20?????????00:00:06?[ksoftirqd/0]
          root?????????5?????2??0?5月20?????????00:00:00?[kworker/0:0H]
          root?????????7?????2??0?5月20?????????00:00:02?[migration/0]
          root?????????8?????2??0?5月20?????????00:00:00?[rcu_bh]
          root?????????9?????2??0?5月20?????????00:30:40?[rcu_sched]
          root????????10?????2??0?5月20?????????00:00:17?[watchdog/0]
          root????????11?????2??0?5月20?????????00:00:16?[watchdog/1]
          root????????12?????2??0?5月20?????????00:00:02?[migration/1]
          root????????13?????2??0?5月20?????????00:00:03?[ksoftirqd/1]
          root????????15?????2??0?5月20?????????00:00:00?[kworker/1:0H]
          root????????17?????2??0?5月20?????????00:00:00?[kdevtmpfs]
          root????????18?????2??0?5月20?????????00:00:00?[netns]
          root????????19?????2??0?5月20?????????00:00:01?[khungtaskd]
          root????????20?????2??0?5月20?????????00:00:00?[writeback]
          root????????21?????2??0?5月20?????????00:00:00?[kintegrityd]
          root????????22?????2??0?5月20?????????00:00:00?[bioset]
          root????????23?????2??0?5月20?????????00:00:00?[kblockd]
          OK,以上每一行都是對一個進程的描述,來具體看一下每個參數(shù)的含義:
          標示
          描述


          UID
          用戶ID
          PID
          進程ID
          PPID
          父進程ID
          C
          進程占cpu百分比
          STIME
          進程啟動的時間
          TTY
          終端機位置
          TIME
          實際使用cpu的時間
          CMD
          命令以及參數(shù)
          我們現(xiàn)在知道了每個參數(shù)的含義,既然講到進程嘛,首先,進程ID是唯一的并且是非負數(shù)的,但是進程ID是可以復(fù)用的,畢竟進程也會終止。
          可以看到?jīng)]有進程PID是0的,這是為什么呢?黑人問號臉?
          0一般來說是系統(tǒng)進程,屬于內(nèi)核的一部分,不執(zhí)行任何磁盤上的程序。

          fork

          一個進程可以通過調(diào)用fork函數(shù)創(chuàng)建新的進程,被創(chuàng)建出來的這個進程就叫子進程。
          這里需要注意一下,fork函數(shù)的返回值父子進程區(qū)別。
          • 子進程 :返回值是0,返回0的理由是子進程的父進程是可以唯一確定的,通過getppid方法可以獲取到父進程id。
          • 父進程 : 返回的是新創(chuàng)建的子進程的id,因為父進程可以有多個子進程,也沒有這樣的函數(shù)可以獲取該線程的子線程的所有id。
          下邊的話我們來驗證一下上說的這一段話。準備好腳本。
          #include?
          #include?
          #include?

          int?main(int?argc,?char?const?*argv[])
          {

          ????pid_t?p1?=?fork();

          ????printf("%d\n",p1);

          ????if(p1?>?0)
          ????{
          ????????printf("父進程?pid?=?%d,?p1?=?%d\n",?getpid(),?p1);
          ????}
          ????else
          ????{
          ????????printf("子進程?pid?=?%d?,?ppid?=?%d,?p1?=?%d\n",?getpid(),?getppid(),?p1);
          ????}

          ????return?0;
          }
          運行看結(jié)果:
          [root@iz2ze76ybn73dvwmdij06zz?~]#?./fork2
          10213
          父進程?pid?=?10212,?p1?=?10213
          0
          子進程?pid?=?10213?,?ppid?=?10212,?p1?=?0
          通過上面的小例子我們可以看到父進程的返回值是子進程的ID,子進程的返回是0。

          孤兒進程

          孤兒我們都懂就是。。。
          是的,沒錯孤兒進程也是這樣的,就是沒有父進程的進程。當然創(chuàng)建的時候肯定是要先創(chuàng)建父進程了,當父進程退出時,它的子進程們(一個或者多個)就成了孤兒進程了。
          接下來在繼續(xù)做一個小測試,讓父進程現(xiàn)退出。準備好腳本。
          [root@iz2ze76ybn73dvwmdij06zz?~]#?cat?guer.c
          #include?
          #include?
          #include?
          #include?


          int?main()
          {
          ????pid_t?pid?=?fork();

          ????if?(pid??perror("fork?error;");
          ????????exit(1);
          ????}?else?if?(pid?==?0)?{
          ?sleep(5);
          ????????printf?("子進程?:?[?pid]?=?%d?,?父進程?[ppid]?=?%d\n",getpid(),getppid());
          ????????exit(0);

          ????}?else?if?(pid?>?0)?{
          ?printf("我是父線程,我先退出一步~\n");
          ?exit(0);

          ????}
          ??return?0;
          }
          執(zhí)行并看結(jié)果:
          到這里估計很多童鞋估計已經(jīng)看懂了,父進程退出后,子進程被一個進程ID為1的進程領(lǐng)養(yǎng)的。還挺好這個結(jié)果,至少還是有人管的,被暖到了~ 進程id為1的進程是init進程,每當有孤兒進程出現(xiàn)時,init進程就會收養(yǎng)它并成為它的父進程 ,來照顧它以孤兒進程以后的生活。

          危害

          因為孤兒進程會被init進程接管,所以孤兒進程是沒有危害的。

          僵尸進程

          和孤兒進程相反的是,這次是子進程先退出,而父進程又沒有去處理回收釋放子進程的資源,這個時候子進程就成了僵尸進程。
          先準備好代碼:
          [root@iz2ze76ybn73dvwmdij06zz?~]#?cat?zombie.c
          ??#include?
          ??#include?
          ??#include?
          ??#include?

          ??int?main()
          ??{
          ??????pid_t?pid;
          ??????pid?=?fork();
          ?????if?(pid??????{
          ?????????perror("fork?error:");
          ?????????exit(1);
          ?????}
          ?????else?if?(pid?==?0)
          ?????{
          ?????????printf("我是子進程,我要先退出一步了.\n");
          ??printf("子進程?id?:?%d\n"?,getpid());
          ?????????exit(0);
          ?????}?else?{
          ?????????printf("我是父進程,我先睡2秒\n");
          ?????????printf("父進程?id?:?%d\n"?,getpid());

          ?????????sleep(2);

          ?????????while(2);?//來個死循環(huán),不退出的那種
          ????}


          ???return?0;
          ?}
          運行看下結(jié)果:
          再來開一個終端看下進程結(jié)果:
          大家可以看到,子進程并沒有完全退出,釋放資源,而是變成了僵尸進程。

          危害

          資源上是占用不了什么資源。但是通常系統(tǒng)的進程數(shù)量都是有限制的,如果有大量的僵尸進程占用進程號,導(dǎo)致新的進程無法創(chuàng)建,這個危害類似于占個坑,不辦事。

          處理

          1.干掉父進程
          干掉父進程后,讓剩下的子進程成為孤兒進程,成為孤兒進程后就和我們上面說的一樣了,由init進程來領(lǐng)養(yǎng)這些進程,并且來處理這些進程的資源釋放等工作。
          2.父進程調(diào)用wait或waitpid
          等函數(shù)等待子進程結(jié)束,這會導(dǎo)致父進程掛起。執(zhí)行wait()或 waitpid()系統(tǒng)調(diào)用,則子進程在終止后會立即把它在進程表中的數(shù)據(jù)返回給父進程,此時系統(tǒng)會立即刪除該進入點。在這種情形下就不會產(chǎn)生defunct進程。
          3.fork兩次
          第一次 fork : 父進程fork一個子進程
          第二次 fork : 子進程fork一個孫進程后退出
          那么孫進程被init接管,當孫進程結(jié)束后,init會回收。
          但子進程的回收還要自己做。
          4.signal函數(shù)
          父進程來處理:用signal函數(shù)為SIGCHLD安裝handler,在子進程結(jié)束后,父進程會收到該信號,可以在handler中調(diào)用wait回收。
          內(nèi)核來處理: 如果父進程不關(guān)心子進程什么時候結(jié)束,可以通過以下兩個函數(shù)通知內(nèi)核自己不感興趣子進程的結(jié)束,此時,子進程結(jié)束后,內(nèi)核會回收并不再給你父進程發(fā)信號。
          • signal(SIGCLD, SIG_IGN)
          • signal(SIGCHLD, SIG_IGN)

          總結(jié)

          本來以為簡單的一個問題,沒想到這個篇幅其實也不算短,所以感覺程序員真的不能說一個什么知識點就簡單,很容易理解啊,一旦你想要深入也是需要一定的時間花費和精力的~

          推薦閱讀:

          互聯(lián)網(wǎng)人辦公地鄙視鏈

          從零開始搭建創(chuàng)業(yè)公司后臺技術(shù)棧

          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機,樹莓派,等等。在公眾號內(nèi)回復(fù)「2048」,即可免費獲取??!

          微信掃描二維碼,關(guān)注我的公眾號

          寫留言

          朕已閱?

          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.男女视频 | 以及视频片又粗又猛 | а中文在线天堂 | 我要看国产一级黄片 | 日韩在线观看中文字幕 |