linux c之信號(hào)signal處理機(jī)制

      網(wǎng)友投稿 1131 2025-03-31

      最近同事的程序設(shè)計(jì)過(guò)程中用到了Linux的signal機(jī)制,從而引發(fā)了我對(duì)Linux中signal機(jī)制的思考。Signal機(jī)制在Linux中是一個(gè)非常常用的進(jìn)程間通信機(jī)制,很多人在使用的時(shí)候不會(huì)考慮該機(jī)制是具體如何實(shí)現(xiàn)的。signal機(jī)制可以被理解成進(jìn)程的軟中斷,因此,在實(shí)時(shí)性方面還是相對(duì)比較高的。Linux中signal機(jī)制的模型可以采用下圖進(jìn)行描述。

      個(gè)進(jìn)程都會(huì)采用一個(gè)進(jìn)程控制塊對(duì)其進(jìn)行描述,進(jìn)程控制塊中設(shè)計(jì)了一個(gè)signal的位圖信息,其中的每位與具體的signal相對(duì)應(yīng),這與中斷機(jī)制是保持一致的。當(dāng)系統(tǒng)中一個(gè)進(jìn)程A通過(guò)signal系統(tǒng)調(diào)用向進(jìn)程B發(fā)送signal時(shí),設(shè)置進(jìn)程B的對(duì)應(yīng)signal位圖,類似于觸發(fā)了signal對(duì)應(yīng)中斷。發(fā)送signal只是“中斷”觸發(fā)的一個(gè)過(guò)程,具體執(zhí)行會(huì)在兩個(gè)階段發(fā)生:

      1、? system call返回。進(jìn)程B由于調(diào)用了system call后,從內(nèi)核返回用戶態(tài)時(shí)需要檢查他擁有的signal位圖信息表,此時(shí)是一個(gè)執(zhí)行點(diǎn)。

      2、? 中斷返回。進(jìn)程被系統(tǒng)中斷打斷之后,系統(tǒng)將CPU交給進(jìn)程時(shí),需要檢查即將執(zhí)行進(jìn)程所擁有的signal位圖信息表,此時(shí)也是一個(gè)執(zhí)行點(diǎn)。

      綜上所述,signal的執(zhí)行點(diǎn)可以理解成從內(nèi)核態(tài)返回用戶態(tài)時(shí),在返回時(shí),如果發(fā)現(xiàn)待執(zhí)行進(jìn)程存在被觸發(fā)的signal,那么在離開(kāi)內(nèi)核態(tài)之后(也就是將CPU切換到用戶模式),執(zhí)行用戶進(jìn)程為該signal綁定的signal處理函數(shù),從這一點(diǎn)上看,signal處理函數(shù)是在用戶進(jìn)程上下文中執(zhí)行的。當(dāng)執(zhí)行完signal處理函數(shù)之后,再返回到用戶進(jìn)程被中斷或者system call(軟中斷或者指令陷阱)打斷的地方。

      Signal機(jī)制實(shí)現(xiàn)的比較靈活,用戶進(jìn)程由于中斷或者system call陷入內(nèi)核之后,將斷點(diǎn)信息都保存到了堆棧中,在內(nèi)核返回用戶態(tài)時(shí),如果存在被觸發(fā)的signal,那么直接將待執(zhí)行的signal處理函數(shù)push到堆棧中,在CPU切換到用戶模式之后,直接pop堆棧就可以執(zhí)行signal處理函數(shù)并且返回到用戶進(jìn)程了。Signal處理函數(shù)應(yīng)用了進(jìn)程上下文,并且應(yīng)用實(shí)際的中斷模擬了進(jìn)程的軟中斷過(guò)程。

      最近寫程序,各種bug各種錯(cuò),有一回程序莫名退出,沒(méi)報(bào)錯(cuò),也沒(méi)產(chǎn)生日志和core文件,貌似正常退出一樣。

      但又不是在程序全部走完后退出,中途莫名退出,這就叫我想到了signal,應(yīng)該是某些函數(shù)錯(cuò)誤后發(fā)送kill信號(hào)給主進(jìn)程,然后退出。

      現(xiàn)在總結(jié)下signal各種類型:

      Signal

      Description

      SIGABRT

      由調(diào)用abort函數(shù)產(chǎn)生,進(jìn)程非正常退出

      SIGALRM

      用alarm函數(shù)設(shè)置的timer超時(shí)或setitimer函數(shù)設(shè)置的interval timer超時(shí)

      SIGBUS

      某種特定的硬件異常,通常由內(nèi)存訪問(wèn)引起

      SIGCANCEL

      由Solaris Thread Library內(nèi)部使用,通常不會(huì)使用

      SIGCHLD

      進(jìn)程Terminate或Stop的時(shí)候,SIGCHLD會(huì)發(fā)送給它的父進(jìn)程。缺省情況下該Signal會(huì)被忽略

      SIGCONT

      當(dāng)被stop的進(jìn)程恢復(fù)運(yùn)行的時(shí)候,自動(dòng)發(fā)送

      SIGEMT

      和實(shí)現(xiàn)相關(guān)的硬件異常

      SIGFPE

      數(shù)學(xué)相關(guān)的異常,如被0除,浮點(diǎn)溢出,等等

      linux c之信號(hào)signal處理機(jī)制

      SIGFREEZE

      Solaris專用,Hiberate或者Suspended時(shí)候發(fā)送

      SIGHUP

      發(fā)送給具有Terminal的Controlling Process,當(dāng)terminal被disconnect時(shí)候發(fā)送

      SIGILL

      非法指令異常

      SIGINFO

      BSD signal。由Status Key產(chǎn)生,通常是CTRL+T。發(fā)送給所有Foreground Group的進(jìn)程

      SIGINT

      由Interrupt Key產(chǎn)生,通常是CTRL+C或者DELETE。發(fā)送給所有ForeGround Group的進(jìn)程

      SIGIO

      異步IO事件

      SIGIOT

      實(shí)現(xiàn)相關(guān)的硬件異常,一般對(duì)應(yīng)SIGABRT

      SIGKILL

      無(wú)法處理和忽略。中止某個(gè)進(jìn)程

      SIGLWP

      由Solaris Thread Libray內(nèi)部使用

      SIGPIPE

      在reader中止之后寫Pipe的時(shí)候發(fā)送

      SIGPOLL

      當(dāng)某個(gè)事件發(fā)送給Pollable Device的時(shí)候發(fā)送

      SIGPROF

      Setitimer指定的Profiling Interval Timer所產(chǎn)生

      SIGPWR

      和系統(tǒng)相關(guān)。和UPS相關(guān)。

      SIGQUIT

      輸入Quit Key的時(shí)候(CTRL+\)發(fā)送給所有Foreground Group的進(jìn)程

      SIGSEGV

      非法內(nèi)存訪問(wèn)

      SIGSTKFLT

      Linux專用,數(shù)學(xué)協(xié)處理器的棧異常

      SIGSTOP

      中止進(jìn)程。無(wú)法處理和忽略。

      SIGSYS

      非法系統(tǒng)調(diào)用

      SIGTERM

      請(qǐng)求中止進(jìn)程,kill命令缺省發(fā)送

      SIGTHAW

      Solaris專用,從Suspend恢復(fù)時(shí)候發(fā)送

      SIGTRAP

      實(shí)現(xiàn)相關(guān)的硬件異常。一般是調(diào)試異常

      SIGTSTP

      Suspend Key,一般是Ctrl+Z。發(fā)送給所有Foreground Group的進(jìn)程

      SIGTTIN

      當(dāng)Background Group的進(jìn)程嘗試讀取Terminal的時(shí)候發(fā)送

      SIGTTOU

      當(dāng)Background Group的進(jìn)程嘗試寫Terminal的時(shí)候發(fā)送

      SIGURG

      當(dāng)out-of-band data接收的時(shí)候可能發(fā)送

      SIGUSR1

      用戶自定義signal 1

      SIGUSR2

      用戶自定義signal 2

      SIGVTALRM

      setitimer函數(shù)設(shè)置的Virtual Interval Timer超時(shí)的時(shí)候

      SIGWAITING

      Solaris Thread Library內(nèi)部實(shí)現(xiàn)專用

      SIGWINCH

      當(dāng)Terminal的窗口大小改變的時(shí)候,發(fā)送給Foreground Group的所有進(jìn)程

      SIGXCPU

      當(dāng)CPU時(shí)間限制超時(shí)的時(shí)候

      SIGXFSZ

      進(jìn)程超過(guò)文件大小限制

      SIGXRES

      Solaris專用,進(jìn)程超過(guò)資源限制的時(shí)候發(fā)送

      signal對(duì)應(yīng)的值:

      POSIX.1中列出的信號(hào):

      SIGHUP 1 A 終端掛起或者控制進(jìn)程終止

      SIGINT 2 A 鍵盤中斷(如break鍵被按下)

      SIGQUIT 3 C 鍵盤的退出鍵被按下

      SIGILL 4 C 非法指令

      SIGABRT 6 C 由abort(3)發(fā)出的退出指令

      SIGFPE 8 C 浮點(diǎn)異常

      SIGKILL 9 AEF Kill信號(hào)

      SIGSEGV 11 C 無(wú)效的內(nèi)存引用

      SIGPIPE 13 A 管道破裂: 寫一個(gè)沒(méi)有讀端口的管道

      SIGALRM 14 A 由alarm(2)發(fā)出的信號(hào)

      SIGTERM 15 A 終止信號(hào)

      SIGUSR1 30,10,16 A 用戶自定義信號(hào)1

      SIGUSR2 31,12,17 A 用戶自定義信號(hào)2

      SIGCHLD 20,17,18 B 子進(jìn)程結(jié)束信號(hào)

      SIGCONT 19,18,25 進(jìn)程繼續(xù)(曾被停止的進(jìn)程)

      SIGSTOP 17,19,23 DEF 終止進(jìn)程

      SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵

      SIGTTIN 21,21,26 D 后臺(tái)進(jìn)程企圖從控制終端讀

      SIGTTOU 22,22,27 D 后臺(tái)進(jìn)程企圖從控制終端寫

      沒(méi)在POSIX.1中列出,而在SUSv2列出

      SIGBUS 10,7,10 C 總線錯(cuò)誤(錯(cuò)誤的內(nèi)存訪問(wèn))

      SIGPOLL A Sys V定義的Pollable事件,與SIGIO同義

      SIGPROF 27,27,29 A Profiling定時(shí)器到

      SIGSYS 12,-,12 C 無(wú)效的系統(tǒng)調(diào)用 (SVID)

      SIGTRAP 5 C 跟蹤/斷點(diǎn)捕獲

      SIGURG 16,23,21 B Socket出現(xiàn)緊急條件(4.2 BSD)

      SIGVTALRM 26,26,28 A 實(shí)際時(shí)間報(bào)警時(shí)鐘信號(hào)(4.2 BSD)

      SIGXCPU 24,24,30 C 超出設(shè)定的CPU時(shí)間限制(4.2 BSD)

      SIGXFSZ 25,25,31 C 超出設(shè)定的文件大小限制(4.2 BSD)

      (對(duì)于SIGSYS,SIGXCPU,SIGXFSZ,以及某些機(jī)器體系結(jié)構(gòu)下的SIGBUS,Linux缺省的動(dòng)作是A (terminate),SUSv2 是C (terminate and dump core))。

      代碼測(cè)試

      #include

      #include

      #include

      #include

      void when_alarm();

      void when_sigint();

      void when_sigchld(int);

      void when_sigusr1();

      void when_sigio();

      int main()

      {

      int childpid;//子程序進(jìn)程ID號(hào)

      printf("程序已經(jīng)開(kāi)始運(yùn)行,5秒鐘后將接收到時(shí)鐘信號(hào)。/n");

      if ((childpid=fork())>0)//父進(jìn)程

      {

      signal(SIGALRM,when_alarm); //當(dāng)接收到SIGALRM信號(hào)時(shí),調(diào)用when_alarm函數(shù)

      signal(SIGINT,when_sigint); //當(dāng)接收到SIGINT信號(hào)時(shí),調(diào)用when_sigint函數(shù)

      signal(SIGCHLD,when_sigchld);//當(dāng)接收到SIGCHLD信號(hào)時(shí),調(diào)用when_sigchld函數(shù)

      signal(SIGUSR1,when_sigusr1);//當(dāng)接收到SIGUSR1信號(hào)時(shí),調(diào)用when_sigusr1函數(shù)

      signal(SIGIO,when_sigio);//當(dāng)接收到SIGIO信號(hào)時(shí),調(diào)用when_sigio函數(shù)

      alarm(5); //5秒鐘之后產(chǎn)生SIGALRM信號(hào)

      raise(SIGIO); //向自己發(fā)送一個(gè)SIGIO信號(hào)

      pause(); //將父進(jìn)程暫停下來(lái),等待SIGALRM信號(hào)到來(lái)

      pause(); //將父進(jìn)程暫停下來(lái),等待SIGUSR1信號(hào)到來(lái)

      pause(); //將父進(jìn)程暫停下來(lái),等待SIGCHLD信號(hào)到來(lái)

      printf("------此時(shí)程序會(huì)停下來(lái)等待,請(qǐng)按下ctrl+c送出SIGINT信號(hào)-------/n");

      pause(); //將父進(jìn)程暫停下來(lái),等待SIGINT信號(hào)到來(lái)

      }

      else if(childpid==0) //子進(jìn)程

      {

      int timer;

      for(timer=7;timer>=0;timer--) //時(shí)鐘計(jì)時(shí)5秒產(chǎn)生SIGALRM信號(hào),再過(guò)2秒子進(jìn)程退出,產(chǎn)生SIGCHLD信號(hào)

      {

      if(timer>2)

      printf("距離SIGALRM信號(hào)到來(lái)還有%d秒。/n",timer-2);

      if(timer==4)

      kill(getppid(),SIGUSR1); //向父進(jìn)程發(fā)送一個(gè)SIGUSR1信號(hào)

      if((timer<=2)&&(timer>0))

      printf("子進(jìn)程還剩%d秒退出,屆時(shí)會(huì)產(chǎn)生SIGCHLD信號(hào)。/n",timer);

      if(timer==0) //子進(jìn)程退出,產(chǎn)生SIGCHLD信號(hào)

      raise(SIGKILL); //子進(jìn)程給自己發(fā)一個(gè)結(jié)束信號(hào)

      sleep(1); //每個(gè)循環(huán)延時(shí)1秒鐘

      }

      }

      else

      printf("fork()函數(shù)調(diào)用出現(xiàn)錯(cuò)誤!/n");

      return 0;

      }

      void when_alarm()

      {

      printf("5秒鐘時(shí)間已到,系統(tǒng)接收到了SIGALRM信號(hào)!/n");

      }

      void when_sigint()

      {

      printf("已經(jīng)接收到了SIGINT信號(hào),程序?qū)⑼顺觯?n");

      exit(0);

      }

      void when_sigchld(int SIGCHLD_num)

      {

      printf("收到SIGCHLD信號(hào),表明我的子進(jìn)程已經(jīng)中止,SIGCHLD信號(hào)的數(shù)值是:%d。/n",SIGCHLD_num);

      }

      void when_sigusr1()

      {

      printf("系統(tǒng)接收到了用戶自定義信號(hào)SIGUSR1。/n");

      }

      void when_sigio()

      {

      printf("系統(tǒng)接收到了SIGIO信號(hào)。/n");

      }

      Linux 任務(wù)調(diào)度

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:WPS怎樣套用表格樣式圖文教程(wps如何套用表格樣式)
      下一篇:Excel 用高級(jí)篩選快速將1970年至1987年1月至3月的日期篩選出來(lái)(excel函數(shù)公式大全)
      相關(guān)文章
      亚洲欧洲自拍拍偷综合| 亚洲精品无码专区2| 久久精品亚洲一区二区| 亚洲字幕AV一区二区三区四区| 亚洲综合另类小说色区色噜噜| 亚洲影视一区二区| 337p日本欧洲亚洲大胆色噜噜| 亚洲乱码中文字幕手机在线| 亚洲av日韩专区在线观看| 亚洲1区1区3区4区产品乱码芒果| 亚洲高清视频免费| 1区1区3区4区产品亚洲| 亚洲综合精品香蕉久久网97| 亚洲国产精品一区二区久久hs| 黑人精品videos亚洲人| 国产精一品亚洲二区在线播放| 亚洲精品国精品久久99热一| 在线观看亚洲精品国产| 国产性爱在线观看亚洲黄色一级片| 亚洲精品国产va在线观看蜜芽| 午夜亚洲国产精品福利| 色偷偷亚洲第一综合| 豆国产96在线|亚洲| yy6080久久亚洲精品| 色天使色婷婷在线影院亚洲| 亚洲精品无码久久久| 在线观看亚洲精品国产| 国产成人无码综合亚洲日韩| 亚洲av无码片在线播放| 亚洲卡一卡2卡三卡4卡无卡三| 亚洲黄色在线观看| 亚洲人成在久久综合网站| 亚洲成A人片在线播放器| 亚洲精品无码不卡在线播放| 亚洲精品精华液一区二区| 亚洲欧美aⅴ在线资源| 国产亚洲精品欧洲在线观看| 亚洲欧洲久久av| 三上悠亚亚洲一区高清| 国产亚洲综合网曝门系列| 亚洲专区先锋影音|