在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

什么是進程

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-08 15:21 ? 次閱讀

在探討這個問題之前,我們先來弄清什么是進程。

進程(Process)是計算機中的程序關于某數據集合上的一次運行活動,是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。程序是指令、數據及其組織形式的描述,進程是程序的實體。進程是一個具有獨立功能的程序關于某個數據集合的一次運行活動。它可以申請和擁有系統資源,是一個動態的概念,是一個活動的實體。它不只是程序的代碼,還包括當前的活動,通過程序計數器的值和處理寄存器的內容來表示。通俗點講,進程是一段程序的執行過程,是個動態概念。

一:進程狀態

圖片

程序運行必須加載在內存中,當有過多的就緒態或阻塞態進程在內存中沒有運行,因為內存很小,有可能不足。系統需要把他們移動到內存外磁盤中,稱為掛起狀態。就緒狀態的進程掛起就是掛起就緒狀態,阻塞進程掛起就稱為阻塞掛起狀態。

每個進程的產生都有自己的唯一的ID號(pid),并且附帶有一個它父進程的ID號(ppid)。進程死亡時,ID被回收。

進程間靠優先級獲得CPU資源,時間片段輪換來更新優先級,以保證不會一個進程占據CPU時間過長。每個進程都得到輪換運行,因為這個時間非常短,所以給我們就好像是系統在同時運行好多進程。

二:僵尸進程

圖片

那么什么稱為僵尸進程呢?

即子進程先于父進程退出后,子進程的PCB需要其父進程釋放,但是父進程并沒有釋放子進程的PCB,這樣的子進程就稱為僵尸進程,僵尸進程實際上是一個已經死掉的進程。我們用代碼來看一下

#include
#include
#include
#include
#include
#include

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

if(pid==0) //子進程
{
printf("child id is %dn",getpid());
printf("parent id is %dn",getppid());
}
else //父進程不退出,使子進程成為僵尸進程
{
while(1)
{}
}
exit(0);
}

我們將它掛在后臺執行,可以看到結果,用ps可以看到子進程后有一個 ,defunct是已死的,僵尸的意思,可以看出這時的子進程已經是一個僵尸進程了。因為子進程已經結束,而其父進程并未釋放其PCB,所以產生了這個僵尸進程。

圖片

我們也可以用ps -aux | grep pid 查看進程狀態

圖片

一個進程在調用exit命令結束自己的生命的時候,其實它并沒有真正的被銷毀,而是留下一個稱為僵尸進程(Zombie)的數據結構(系統調用exit,它的作用是使進程退出,但也僅僅限于將一個正常的進程變成一個僵尸進程,并不能將其完全銷毀)。在Linux進程的狀態中,僵尸進程是非常特殊的一種,它已經放棄了幾乎所有內存空間,沒有任何可執行代碼,也不能被調度,僅僅在進程列表中保留一個位置,記載該進程的退出狀態等信息供其他進程收集,除此之外,僵尸進程不再占有任何內存空間。這個僵尸進程需要它的父進程來為它收尸,如果他的父進程沒有處理這個僵尸進程的措施,那么它就一直保持僵尸狀態,如果這時父進程結束了,那么init進程自動會接手這個子進程,為它收尸,它還是能被清除的。但是如果如果父進程是一個循環,不會結束,那么子進程就會一直保持僵尸狀態,這就是為什么系統中有時會有很多的僵尸進程。

試想一下,如果有大量的僵尸進程駐在系統之中,必然消耗大量的系統資源。但是系統資源是有限的,因此當僵尸進程達到一定數目時,系統因缺乏資源而導致奔潰。所以在實際編程中,避免和防范僵尸進程的產生顯得尤為重要。

三:孤兒進程

一個父進程退出,而它的一個或多個子進程還在運行,那么那些子進程將成為孤兒進程。孤兒進程將被init進程(進程號為1)所收養,并由init進程對它們完成狀態收集工作。

子進程死亡需要父進程來處理,那么意味著正常的進程應該是子進程先于父進程死亡。當父進程先于子進程死亡時,子進程死亡時沒父進程處理,這個死亡的子進程就是孤兒進程。

但孤兒進程與僵尸進程不同的是,由于父進程已經死亡,系統會幫助父進程回收處理孤兒進程。所以孤兒進程實際上是不占用資源的,因為它終究是被系統回收了。不會像僵尸進程那樣占用ID,損害運行系統。

下來我們上代碼看看:

#include
#include
#include
#include
#include
#include

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

if(pid==0)
{
printf("child ppid is %dn",getppid());
sleep(10); //為了讓父進程先結束
printf("child ppid is %dn",getppid());
}
else
{
printf("parent id is %dn",getpid());
}

exit(0);
}

圖片

從執行結果來看,此時由pid == 4168父進程創建的子進程,其輸出的父進程pid == 1,說明當其為孤兒進程時被init進程回收,最終并不會占用資源,這就是為什么要將孤兒進程分配給init進程。

四:僵尸進程處理方式

任何一個子進程(init除外)在exit()之后,并非馬上就消失掉,而是留下一個稱為僵尸進程(Zombie)的數據結構,等待父進程處理。這是每個子進程在結束時都要經過的階段。如果子進程在exit()之后,父進程沒有來得及處理,這時用ps命令就能看到子進程的狀態是“defunct”。如果父進程能及時處理,可能用ps命令就來不及看到子進程的僵尸狀態,但這并不等于子進程不經過僵尸狀態。如果父進程在子進程結束之前退出,則子進程將由init接管。init將會以父進程的身份對僵尸狀態的子進程進行處理。所以孤兒進程不會占資源,僵尸進程會占用資源危害系統。我們應當避免僵尸進程的出現。

解決方式如下:

1):一種比較暴力的做法是將其父進程殺死,那么它的子進程,即僵尸進程會變成孤兒進程,由系統來回收。但是這種做法在大多數情況下都是不可取的,如父進程是一個服務器程序,如果為了回收其子進程的資源,而殺死服務器程序,那么將導致整個服務器崩潰,得不償失。顯然這種回收進程的方式是不可取的,但其也有一定的存在意義。

2):SIGCHLD信號處理

我們都知道wait函數是用來處理僵尸進程的,但是進程一旦調用了wait,就立即阻塞自己,由wait自動分析是否當前進程的某個子進程已經退出,如果讓它找到了這樣一個已經變成僵尸的子進程,wait就會收集這個子進程的信息,并把它徹底銷毀后返回;如果沒有找到這樣一個子進程,wait就會一直阻塞在這里,直到有一個出現為止。我們先來看看wait函數的定義

#include /* 提供類型pid_t的定義,實際就是int型 */

#include

pid_t wait(int *status)

參數status用來保存被收集進程退出時的一些狀態,它是一個指向int類型的指針。但如果我們對這個子進程是如何死掉的毫不在意,只想把這個僵尸進程消滅掉,(事實上絕大多數情況下,我們都會這樣想),我們就可以設定這個參數為NULL,就象下面這樣:pid=wait(NULL);如果成功,wait會返回被收集的子進程的進程ID,如果調用進程沒有子進程,調用就會失敗,此時wait返回-1,同時errno被置為ECHILD。

由于調用wait之后,就必須阻塞,直到有子進程結束,所以,這樣來說是非常不高效的,我們的父進程難道要一直等待你子進程完成,最后才能執行自己的代碼嗎?難道就不能我父進程執行自己的代碼,你子進程什么時候完成我就什么時候去處理你,不用一直等你?當然是有這種方式了。

實際上當子進程終止時,內核就會向它的父進程發送一個SIGCHLD信號,父進程可以選擇忽略該信號,也可以提供一個接收到信號以后的處理函數。對于這種信號的系統默認動作是忽略它。我們不希望有過多的僵尸進程產生,所以當父進程接收到SIGCHLD信號后就應該調用 wait 或 waitpid 函數對子進程進行善后處理,釋放子進程占用的資源。

下面是一個處理僵尸進程的簡單的例子:

#include
#include
#include
#include
#include
#include
#include
#include

void deal_child(int num)
{
printf("deal_child inton");
wait(NULL);
}

int main()
{
signal(SIGCHLD,deal_child);
pid_t pid=fork();
int i;

if(pid==0)
{
printf("child is runningn");
sleep(2);
printf("child will endn");
}
else
{
sleep(1); //讓子進程先執行
printf("parent is runningn");
sleep(10); //一旦被打斷就不能再進入睡眠
printf("sleep 10 s overn");
sleep(5);
printf("sleep 5s overn");
}

exit(0);
}

進行測試后確定了是在父進程睡眠10s時子進程結束,父進程接收到了SIGCHLD信號,調用了deal_child函數,釋放了子進程的PCB后又回到自己本身的代碼中執行。我們看看運行結果

圖片

說到這里,我們再來看看signal函數(不是阻塞函數)

signal(參數1,參數2);

參數1:我們要進行處理的信號。系統的信號我們可以再終端鍵入 kill -l查看(共64個)。其實這些信號是系統定義的宏。

參數2:我們處理的方式(是系統默認還是忽略還是捕獲)。

eg: signal(SIGINT ,SIG_ING ); //SIG_ING 代表忽略SIGINT信號

eg:signal(SIGINT,SIG_DFL); //SIGINT信號代表由InterruptKey產生,通常是CTRL +C或者是DELETE。發送給所有ForeGroundGroup的進程。SIG_DFL代表執行系統默認操作,其實對于大多數信號的系統默認動作是終止該進程。這與不寫此處理函數是一樣的。

我們也可以給參數2傳遞一個信號處理函數的地址,但是這個信號處理函數需要其返回值為void,并且默認自帶一個int類型參數

這個int就是你所傳遞的第一個信號參數的值(你用kill -l可以查看)

我們測試了一下,如果創建了5個子進程,但是銷毀的時候仍然有兩個仍是僵尸進程,這又是為什么呢?

這是因為當5個進程同時終止的時候,內核都會向父進程發送SIGCHLD信號,而父進程此時有可能仍然處于信號處理的deal_child函數中,那么在處理完之前,中間接收到的SIGCHLD信號就會丟失,內核并沒有使用隊列等方式來存儲同一種信號

所以為了解決這一問題,我們需要調用waitpid函數來清理子進程。

void deal_child(int sig_no)

{

for (;;) {

if (waitpid(-1, NULL, WNOHANG) == 0)

break;

}

}

這樣的話,只有檢驗沒有僵尸進程,他才會返回0,這樣就可以確保所有的僵尸進程都被殺死了。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 計算機
    +關注

    關注

    19

    文章

    7529

    瀏覽量

    88408
  • 程序
    +關注

    關注

    117

    文章

    3794

    瀏覽量

    81269
  • 數據集
    +關注

    關注

    4

    文章

    1209

    瀏覽量

    24772
  • 進程
    +關注

    關注

    0

    文章

    204

    瀏覽量

    13973
收藏 人收藏

    評論

    相關推薦

    Linux 查看進程和刪除進程

    ps 命令用于查看當前正在運行的進程。grep 是搜索例如: ps -ef | grep java表示查看所有進程里 CMD 是 java 的進程信息ps -aux | grep java-aux 顯示
    發表于 04-24 00:04

    【Linux學習雜談】之父進程回收子進程

    進程用wait函數回收子進程wait的工作原理:(1)子進程結束時,系統向其父進程發送SIGCHILD信號(2)父進程調用wait函數之后
    發表于 09-08 13:13

    孤兒進程和僵尸進程

    前段時間,由于研究經典面試題,把孤兒進程和僵尸進程也總結了一下。我們有這樣一個問題:孤兒進程和僵尸進程,怎么產生的?有什么危害?怎么去預防?下面是針對此問題的總結與概括。一.產生的原因
    發表于 11-29 14:08

    怎么區別父進程和子進程

    怎么區別父進程和子進程? 各位大神
    發表于 01-11 17:15

    Linux下的進程結構

    進程不但包括程序的指令和數據,而且包括程序計數器和處理器的所有寄存器及存儲臨時數據的進程堆棧,因此正在執行的進程包括處理器當前的一切活動。 因為Linux是一個多進程的操作系統,所以其
    發表于 05-27 09:24

    什么是僵尸進程和孤兒進程

    在UNIX里,除了進程0(即PID=0的交換進程,Swapper Process)以外的所有進程都是由其他進程使用系統調用fork創建的,這里調用fork創建新
    發表于 08-02 08:36

    詳解linux進程管理

    進程需要了解 進程,父進程進程組,會話和控制終端的相關概念。進程和父進程:每個
    發表于 08-07 08:28

    【工程源碼】Linux 查看進程和刪除進程

    (前提是要有這個東西,例如在裝了 tomcat 的前提下, 輸入 tomcat 的 to 按 tab)。ps 命令用于查看當前正在運行的進程。grep 是搜索例如: ps -ef | grep
    發表于 02-23 20:05

    什么是進程

    什么是進程進程可以理解為正在運行的程序。我們編寫好的代碼,經過編譯后生成一個可執行的文件,我們稱作一個程序。當運行可執行文件后,操作系統會執行可執行文件中的代碼,在CPU上運行的這組代碼被稱做進程
    發表于 12-14 08:26

    進程是什么?進程與程序的區別在哪

    進程是什么?進程與程序的區別在哪?進程的狀態有哪幾種?
    發表于 12-23 06:27

    進程有幾種狀態?

    文章目錄操作系統進程和線程什么是進程?什么是線程?進程和線程有什么區別?何時使用多進程,何時使用多線程?進程有幾種狀態?畫一下
    發表于 12-24 07:16

    Linux進程管理

    Linux進程管理 本章主要介紹進程的概念、狀態、構成以及Linux進程的相關知識。 掌握進程的概念 掌握進程的描述、狀態及轉換 理
    發表于 04-28 14:57 ?0次下載

    Linux進程管理:什么是進程進程的生命周期

    所有運行在Linux操作系統中的進程都被task_struct結構管理,該結構同時被叫作進程描述。一個進程描述包含一個運行進程所有的必要信息,例如
    的頭像 發表于 02-15 14:29 ?8042次閱讀
    Linux<b class='flag-5'>進程</b>管理:什么是<b class='flag-5'>進程</b>?<b class='flag-5'>進程</b>的生命周期

    Linux進程基礎

    進程(process)的區別又是什么呢?進程是程序的一個具體實現。只有食譜沒什么用,我們總要按照食譜的指點真正一步步實行,才能做出菜肴。進程是執行程序的過程,類似于按照食譜,真正去做菜的過程。同一個程序
    發表于 04-02 14:50 ?292次閱讀

    fork出的進程的父進程是從哪來的

    一、粉絲提問fork出的進程的父進程是從哪來的?粉絲提問,一口君必須滿足粉絲提問二、解答這個問題看上去很簡單,但是要想把進程的父進程相關的所有知識點搞清楚,還是有點難度的,下面我們稍微
    的頭像 發表于 12-24 18:41 ?906次閱讀
    主站蜘蛛池模板: 久久久久免费| 国产精品美女一级在线观看| 国产美女视频一区二区二三区 | 欧美啊片| 国产香蕉精品视频在| 欧美色网在线| 亚洲成人网页| 最新毛片网| 四虎影片国产精品8848| 欧美精品专区55页| 国产一级aaa全黄毛片| 2018天天射| 日本黄页网址| 性欧美精品| 卡2卡三卡四卡精品公司 | www.av毛片| 制服丝袜国产精品| 在线播放亚洲视频| 色狠狠综合网| 国产三级跑| 午夜精品久久久久久久久| 国产在线观看午夜不卡| free性乌克兰高清videos| 国产成人精品系列在线观看 | 国产亚洲精品免费| 色盈盈| 黄页在线播放网址| 午夜在线观看福利| 中文4480yy私人免费影院| 美欧毛片| 色多多免费视频观看区一区| 国产亚洲精品在天天在线麻豆| 五月婷婷天| 分分精品| 天堂tv亚洲tv日本tv欧美人tv| 久久久久久久综合| 天堂中文在线最新版地址| 国产精品夜色7777青苹果| 性色小视频| 国产色婷婷精品综合在线手机播放| 天天爱添天天爱添天天爱添|