signal------SIGCHLD

因為筆者之前的文章里面有錯誤,今天發現,立馬做個修改。在下面我的一段關于sigchld信號相對于直接調用wait函數的好處時,我說調用wait函數要一直檢測子進程是否執行完其實是錯誤的, wait是阻塞函數,當主進程調用wait函數的時,主進程處于阻塞狀態,并沒有一直檢測的動作,他只是在等待,假設我們有三個子進程(編號1,2,3)假設2,3進程先執行完,然而1號子進程還沒有執行完,那么主進程的wait就一直處于阻塞狀態,這時候2,3可能產生僵尸進程。這里sigchld和wait的區別就很明顯了。

先來看看信號的基本概念:

信號kill-l查看linux信號及其宏定義編號,其中1~31非實時編號(發送的信號可能丟失,不支持信號排隊),31~64實時信號,發送的信號都會被接收(支持信號排隊)
信號的定義在/usr/include/bits/signum.h
1.信號是軟件中斷
2.信號是異步信號
3.信號的來源:
(1)、硬件來源:主要是硬件的驅動產生,如鍵盤,鼠標等
(2)、軟件來源:主要是一些信號函數、比如kill()、raise()、alarm()、setitimer()等函數,軟件來源包括一些非法運算等操作,軟件設置條件(gdb調試),信號由內核產生
#信號的處理
進程會采取三種方式響應和處理信號
1.忽略信號,sigkill和sigstop永遠不被忽略,忽略硬件異常、進程啟動時,sigusr1和sigusr2被忽略
2.執行默認操作
3.捕獲信號。告訴內核信號出現時調用自己的處理函數,SIGKILL和SIGSTOP不能被捕獲

#信號登記
void(*signal(int signo,void (*func)(int))(int)
signo--要登記的信號編號或者信號宏
func--信號處理函數指針、忽略信號(SIG_IGN)、默認信號(SIG_DEF)

今天我就不針對每個信號詳細介紹了,你也沒必要知道那么多信號,今天介紹一個很重要的信號,SIGCHLD這個信號的作用如下:

SIGCHLD?子進程狀態發生變化產生該信號(子進程運行結束)父進程調用wait函數,回收子進程的進程表項,task_struct結構體。有了這個信號父進程不需要處于阻塞狀態,任然可以干其他事情,當子進程結束時發送一個SIGCHLD信號給父進程,父進程調用wait回收子進程,避免僵尸進程的產生,提高了資源利用率。

?

再了解這個信號之前,先來簡單了解一下wait()函數:

?

pid_t wait(int *status)//狀態
<unistd.h>
<sys/wait.h>
等待子進程退出并回收,防止僵尸進程(子進程運行結束,但是內核中的task_struct沒有釋放)產生,凡是調用wait()就會阻塞,父進程等待,定時檢查子進程是否執行完畢
返回子進程id
pid_t waitpid(pid_t pid, int *status, int options);
成功返回子進程id,這是wait的非阻塞版本。

wait和waitpid區別:
1.在一個子進程終止前,wait使調用者阻塞
2.waitpid有一個選擇項,可以使調用者不阻塞
3。waitpid可以等待指定的一個子進程,wait等待所有的子進程,返回任意一個種植的子進程狀態。
子進程在運行中有暫停信號如果想要顯示暫停信號的信號碼不能使用wait()要用waitpid()

waitpid的宏WNOHANG(非阻塞)WUNTRACED(監聽信號)


我們處理僵尸進程有兩種方式:
1.kill -9 父進程 讓init進程回收僵尸進程
2.wait() 和 waitpid()讓父進程等待回收子進程

下面我們來使用信號實現解決和避免僵尸進程的第三種的方式:

[cpp]?view plain?copy

  1. #include<stdio.h>??
  2. #include<stdlib.h>??
  3. #include<sys/wait.h>??
  4. #include<signal.h>??
  5. void?sig_handler(int?signo)??
  6. {??
  7. ????printf("child?process??%d?stop\n",?signo);??
  8. ??
  9. }??
  10. void?out(int?n)??
  11. {??
  12. ????for(int?i?=?0;?i?<?n;?++i)??
  13. ????{??
  14. ????????printf("%d?out?%d\n",?getpid(),?i);??
  15. ????????sleep(1);??
  16. ????}??
  17. }??
  18. int?main(void)??
  19. {??
  20. ????if(signal(SIGCHLD,?sig_handler)?==?SIG_ERR)??
  21. ????{??
  22. ????????perror("sigchld?error");??
  23. ????????exit(1);??
  24. ????}??
  25. ????pid_t?pid?=?fork();??
  26. ????if(pid?<?0)??
  27. ????{??
  28. ????????perror("fork?error");??
  29. ????????exit(1);??
  30. ????}??
  31. ????else?if(pid?>?0)??
  32. ????{??
  33. ????????out(100);??
  34. ????}??
  35. ????else??
  36. ????{??
  37. ????????out(20);??
  38. ????}??
  39. ????return?0;??
  40. }??


這段代碼使用signal系統調用來捕獲信號,我們在signal里面注冊了SIGCHLD信號,程序中我們讓子進程現執行完,然后捕獲子進程執行完畢的信號。

下面是運行結果部分截圖:

?

這里進程pid3546為父進程3547為子進程

我們再次運行程序來觀察程序的運行狀態,把程序編譯gcc signal_sigchld.c -o child

運行程序./child

使用命令ps -aux|grep child 來觀察程序運行狀態,下面是結果截圖

你可以看到父子進程在子進程運行到20以前都處于S+即運行狀態,當子進程到達20的時候,signal捕獲到子進程退出的信號SIGCHLD

這時候子進程狀態變為Z+即僵尸進程。

?

所以我們說了那么多,為什么SIGCHLD沒有處理這個僵尸進程呢,這里我們要搞清楚,SIGCHLD只是子進程在運行結束的時候產生的一i個信號,我們要想處理這個僵尸狀態,還是要用到上面說的兩種方式。最好就是父進程調用wait(),你可能有要問,既然都要用到wait,那抹干嗎多此一舉使用信號呢?首先要知道父進程調用wait以后處于阻塞狀態,父進程不能干其他事情,使用效率降低,資源利用率低下,增加了開銷,而調用信號以后,當子進程執行完畢以后,自動產再生一個信號給父進程,父進程收到信號以后就調用wait揮手子進程沒有釋放的資源。這樣我的感覺就是子進程化被動為主動。父進程的工作也輕松了不少,可以做自己想做的事情。

?

所以為了避免僵尸進程的產生我們修改上面的代碼中的sig_handler函數如下:

[cpp]?view plain?copy

  1. void?sig_handler(int?signo)??
  2. {??
  3. ????printf("child?process??%d?stop\n",?signo);??
  4. ????wait(0);??
  5. }??

當父進程捕獲到SIGCHLD后調用wait。

按照上述步驟重新編譯,運行,用ps觀察進程運行狀態:

上面是子進程運行到20之前,下面看子進程運行完畢,父進程捕獲到SIGCHLD以后

這里你發現子進程沒有顯示,是因為紫禁城已經被回收釋放掉了。

這就是處理僵尸進程的第三種方式。

也是一種異步處理方式。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384750.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384750.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384750.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

為什么要學習匯編語言?如何正確學習匯編語言?

匯編語言是計算機系統結構的接口&#xff0c;它介于軟硬件之間&#xff0c;學習的時候&#xff0c;必須結合軟件和硬件來學習。 1 向上結合高級語言 學習匯編語言的時候&#xff0c;不可孤立學習匯編語言&#xff0c;當今時代很少之間用到匯編語言編程&#xff0c;但是使用匯…

數據庫Sqlite3

sqlite3 數據庫安裝 1. 本地安裝 sudo dpkg -i *.deb 2.在線安裝 sudo apt-get install sqlite3 SQLITE3 基本命令 兩種命令 1.以 . 開頭的稱之為系統命令 .help 幫助 .quit 退出 .exit 退出 .databases 查看打開的數據庫&#xff08;顯示數據庫的名字和路徑&#xff…

【匯編語言】(王爽)實驗4解答

題目1 編程&#xff1a;向內存0:200 - 0:23F 中存放數據 0 - 3FH ; 向內存 0:200 ~ 0:23f 寫入數據0~3fH【字節型數據】 assume cs:code code segmentstart:mov ax,0mov ds,axmov bx,0200H ; 偏移地址mov al,0 ; 數據mov cx,03fH1H ; 0 ~ 3FH 共 (3F 1)Hs:mov [bx],alinc b…

軟考安全工程師歷年真題匯總

2019年上半年信息安全工程師考試真題與答案&#xff08;下午題&#xff09; https://blog.csdn.net/jayjaydream/article/details/90683127 2018年上半年信息安全工程師考試真題與答案&#xff08;上午題&#xff09; https://www.moondream.cn/?p681 2018年上半年信息安全工…

【匯編語言】8086匯編,快速搞定各種尋址方式:立即數尋址 / 寄存器尋址 / 存儲器尋址

0 前言 眾所周知&#xff0c;對于8086匯編語言&#xff0c;有幾大尋址方式&#xff0c;不過我覺得這個好墨跡&#xff0c;會用就可以了&#xff0c;為什么命名這么多&#xff0c;這次只說本質&#xff0c;不說命名&#xff0c;至于命名&#xff0c;還是得知道&#xff0c;畢竟…

信息安全工程師考試大綱(含pdf)

PDF文件下載鏈接&#xff1a; https://pan.baidu.com/s/1nSLBGfBc8HzFwE0xk9FzcQ 提取碼&#xff1a;9udy 信息安全工程師考試大綱 1&#xff0e;信息安全基本知識 1.1 信息安全概念 ● 了解網絡空間的概…

【數據庫】數據庫基本概念:數據庫管理系統 / 數據庫 / 表 / 數據

0 前言 本文講解數據庫的最基本概念 推薦書籍&#xff1a;《MySQL 必知必會》 需要的軟件&#xff1a;MySQL 8.0 1 數據庫相關概念及其實戰應用 1.1 數據&#xff08;Data&#xff09; 在人類世界中&#xff0c;數據可以是 數值型數據 十進制數 非數值型數據 圖片聲音視頻文…

tiny4412初期環境搭建

花了整整三天 從躍躍欲試到失望 絕望 最后迎來曙光!!! 話不多說直接上干貨 這些軟件安裝的具體過程網上有很多 在這里就不說了 1.在主機下 安裝secureCRT軟件和超級終端&#xff08;安一個就行 不過最好兩個都安上&#xff09; 作用&#xff1a; 軟件可以打印一些開發板信息…

vivado軟件如何查看內部器件的仿真信號

有時候&#xff0c;我們需要查看內部模塊的信號&#xff0c;那么&#xff0c;在vivado軟件該如何操作呢&#xff1f; 運行仿真&#xff0c;可以得到這個界面&#xff0c;之后看左側部分&#xff0c;可以查看內部的模塊。 例如單擊rom0 可以看見其內部信號&#xff0c;然后在想…

通過Source insight查看內核源碼

1.下載源碼 https://www.kernel.org/pub/linux/kernel/ 下載后解壓即可 2.打開SourceInsight,創建工程 點擊頂部Project菜單 3.將源碼文件導入工程 4.查看源碼

藍橋杯物聯網例程下載

今年是藍橋杯物聯網的第一屆 我也是趕快買了物聯網的開發板 這是附帶的例程和一些綜合實驗 僅供參考練習 里面所有的例程大概花了兩周實現了大部分&#xff08;有一些例如ADC和PWM的 手頭沒有示波器和電壓表就沒有做&#xff09; 我比較懶 不喜歡做每個例程的教程 就統一分享出…

Vivado軟件(用VerilogHDL)如何使用$readmemh和$readmemb函數

0 前言 博主我查了很多資料&#xff0c;雖然會使用Verilog的readmemh和readmemh和readmemh和readmemb函數&#xff0c;可是&#xff0c;在vivado軟件中怎么用&#xff1f;文件放在哪里&#xff1f;沒有一篇文章提及。 花了幾個小時&#xff0c;終于研究明白了&#xff0c;特此…

【匯編語言】王爽第六章程序6.3解答,8086匯編語言實現數據的倒序存放

程序很簡單&#xff0c;就是利用棧&#xff0c;實現數據的倒序存放。 ; 將數據逆序存放 assume ds:data data segment dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h data endsassume ss:stack stack segmentdw 0,0,0,0,0,0,0,0 stack endsassume cs:code code segmen…

---------愿 青春與我皆不付---------------------

2019年8月4日晚 21點51 我愿以此用博客來記錄我的學習之路 void mian(void) { while(1) { run(); } } 不負光陰 不負卿

【匯編語言】快速理解什么是尋址,什么是尋址方式

0 前言 有很多專業的資料講述這些概念&#xff0c;但是&#xff0c;雖然很專業&#xff0c;但是初學者根本看不懂&#xff01; 因此在這里&#xff0c;我用最簡單的方式&#xff0c;告訴你 什么是尋址什么是尋址方式 1 計算機的極簡模型 計算機的世界中&#xff0c;只有二…

【匯編語言】程序設計過程,如何避免數據類型匹配錯誤?

真言&#xff1a;操作數據&#xff0c;先看方式&#xff0c;再對應解決 0 前言 對于x86系列的匯編語言&#xff0c;AT&T格式需要使用后綴指明操作數的數據類型&#xff0c;Intel格式并沒有這樣的規定&#xff0c;但是&#xff0c;數據類型還是必須匹配&#xff0c;這就導…

【匯編語言】王爽實驗5(5)(6)的解答 建立數據類型匹配的觀念

0 前言 本文解答王爽《匯編語言》實驗5的&#xff08;5&#xff09;&#xff08;6&#xff09;題 同時給出一些常見問題的解答 以及給出最易犯錯的地方&#xff1a;數據類型不匹配的解決方案 1 題目解答 1.1 實驗5&#xff08;5&#xff09; 1.1.1 題目 將data1和data2段…

【Java圖文趣味版】快速搞定數組的聲明、開辟空間和初始化賦值

0 前言 本文講解java數組的基礎知識&#xff0c;適合零基礎小白。 1 數組的概念 所謂數組&#xff0c;就是一組同類型東西的集合&#xff0c;可以通過index&#xff08;索引&#xff0c;下標&#xff09;訪問這一組東西的某一個元素。 就像下圖這樣&#xff0c;由于數組概念…

【java圖文趣味版】數組元素的訪問與遍歷

0 前言 本文適合零基礎小白。 本文接上一篇文章&#xff1a;快速搞定數組的聲明、開辟空間和初始化賦值 重要的知識點 通過array index訪問數組使用for each循環遍歷數組使用Arrays.toString()方法打印數組 我們先創建一個數組&#xff0c;之后通過它來說明后面的知識。 …

初來乍到,多多關照。

從今天開始就要開始寫博客了&#xff0c;把學到的知識都在這里記錄下來&#xff0c;希望可以堅持&#xff0c;并且學到東西。