久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux | 一篇文章徹底搞定信號(hào),!

 mynotebook 2022-10-31 發(fā)布于湖南


圖片

 1

1.信號(hào)是什么,?

信號(hào)其實(shí)就是一個(gè)軟件中斷。

例:

  1. 輸入命令,,在Shell下啟動(dòng)一個(gè)前臺(tái)進(jìn)程,。
  2. 用戶按下Ctrl-C,鍵盤(pán)輸入產(chǎn)生一個(gè)硬件中斷,。
  3. 如果CPU當(dāng)前正在執(zhí)行這個(gè)進(jìn)程的代碼,,則該進(jìn)程的用戶空間代碼暫停執(zhí)行, CPU從用戶態(tài)切換到內(nèi)核態(tài)處理硬件中斷,。
  4. 終端驅(qū)動(dòng)程序?qū)trl-C解釋成一個(gè)SIGINT信號(hào),,記在該進(jìn)程的PCB中(也可以說(shuō)發(fā)送了一個(gè)SIGINT信號(hào)給該進(jìn)程)。
  5. 當(dāng)某個(gè)時(shí)刻要從內(nèi)核返回到該進(jìn)程的用戶空間代碼繼續(xù)執(zhí)行之前,,首先處理PCB中記錄的信號(hào),,發(fā)現(xiàn)有一個(gè)SIGINT信號(hào)待處理,而這個(gè)信號(hào)的默認(rèn)處理動(dòng)作是終止進(jìn)程,,所以直接終止進(jìn)程而不再返回它的用戶空間代碼執(zhí)行,。

在這個(gè)例子中,,由ctrl+c產(chǎn)生的硬件中斷就是一個(gè)信號(hào),。Ctrl+C產(chǎn)生的信號(hào)只能發(fā)送給前臺(tái)進(jìn)程,,命令后加&就可放到后臺(tái)運(yùn)行。 Shell可同時(shí)運(yùn)行一個(gè)前臺(tái)進(jìn)程和任意多個(gè)后臺(tái)進(jìn)程,,只有前臺(tái)進(jìn)程才能接受到像CTRL+C這種控制鍵產(chǎn)生的信號(hào),。

2.信號(hào)的種類

使用命令查看:

kill -l

非可靠信號(hào):1~31號(hào)信號(hào),信號(hào)可能會(huì)丟失 可靠信號(hào):34~64號(hào)信號(hào),,信號(hào)不可能丟失

圖片

SIGHUP:1號(hào)信號(hào),,Hangup detected on controlling terminal or death of controlling process(在控制終端上掛起信號(hào),或讓進(jìn)程結(jié)束),,ation:term

SIGINT:2號(hào)信號(hào),,Interrupt from keyboard(鍵盤(pán)輸入中斷,ctrl + c ),,action:term

SIGQUIT:3號(hào)信號(hào),,Quit from keyboard(鍵盤(pán)輸入退出,ctrl+ | ),,action:core,,產(chǎn)生core dump文件

SIGABRT:6號(hào)信號(hào),Abort signal from abort(3)(非正常終止,,double free),,action:core

SIGKILL:9號(hào)信號(hào),Kill signal(殺死進(jìn)程信號(hào)),,action:term,,該信號(hào)不能被阻塞、忽略,、自定義處理

SIGSEGV:11號(hào)信號(hào),,Invalid memory reference(無(wú)效的內(nèi)存引用,解引用空指針,、內(nèi)存越界訪問(wèn)),,action:core

SIGPIPE:13號(hào)信號(hào),Broken pipe: write to pipe with no readers(管道中止: 寫(xiě)入無(wú)人讀取的管道,,會(huì)導(dǎo)致管道破裂),,action:term

SIGCHLD:17號(hào)信號(hào),Child stopped or terminated(子進(jìn)程發(fā)送給父進(jìn)程的信號(hào),,但該信號(hào)為忽略處理的)

SIGSTOP:19號(hào)信號(hào),,Stop process(停止進(jìn)程),action:stop

SIGTSTP:20號(hào)信號(hào),,Stop typed at terminal(終端上發(fā)出的停止信號(hào),,ctrl + z),,action:stop

具體的信號(hào)采取的動(dòng)作和詳細(xì)信息可查看:man 7 signal

3.信號(hào)的產(chǎn)生

3.1硬件產(chǎn)生

硬件產(chǎn)生即通過(guò)終端按鍵產(chǎn)生的信號(hào):

  1. ctrl + c:SIGINT(2),發(fā)送給前臺(tái)進(jìn)程,,& 進(jìn)程放到后臺(tái)運(yùn)行,,fg 把剛剛放到后臺(tái)的進(jìn)程,再放到前臺(tái)來(lái)運(yùn)行
  2. ctrl + z:SIGTSTP(20),,一般不用,,除非有特定場(chǎng)景
  3. ctrl + | :SIGQUIT(3),產(chǎn)生core dump文件

產(chǎn)生core dump文件的條件:

當(dāng)前OS一定不要限制core dump文件的大小,,ulimit -a
磁盤(pán)空間要足夠
如何產(chǎn)生:
3.1 解引用空指針,,收到11號(hào)信號(hào),產(chǎn)生core dump文件
3.2 內(nèi)存訪問(wèn)越界,,程序一旦崩潰,,就會(huì)收到11號(hào)信號(hào),也就會(huì)產(chǎn)生core dump文件
3.3 double free,,收到6號(hào)信號(hào),,并產(chǎn)生core dump。
3.4 free(NULL),,不會(huì)崩潰

3.2軟件產(chǎn)生

軟件產(chǎn)生即調(diào)用系統(tǒng)函數(shù)向進(jìn)程發(fā)信號(hào)

  1. kill函數(shù)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
參數(shù)解釋:
pid:進(jìn)程號(hào)
sig:要發(fā)送的信號(hào)值
返回值:成功返回0,,失敗返回-1,并設(shè)置錯(cuò)誤
  1. kill命令:kill -[信號(hào)] pid,,
  2. abort:void abort(void);,,收到6號(hào)信號(hào),誰(shuí)調(diào)用該函數(shù),,誰(shuí)就收到信號(hào)
  3. alarm:unsigned int alarm(unsigned int seconds);,,收到14號(hào)信號(hào),告訴內(nèi)核在seconds秒后給進(jìn)程發(fā)送SIGALRM信號(hào),,該信號(hào)默認(rèn)處理動(dòng)作為終止當(dāng)前進(jìn)程,。

4.信號(hào)的注冊(cè)

信號(hào)注冊(cè)又分為可靠信號(hào)的注冊(cè)和非可靠信號(hào)的注冊(cè)。 信號(hào)注冊(cè)實(shí)際上是一個(gè)位圖和一個(gè)sigqueue隊(duì)列,。圖片

4.1非可靠信號(hào)的注冊(cè)

當(dāng)進(jìn)程收到非可靠信號(hào)時(shí):

  1. 將非可靠信號(hào)對(duì)應(yīng)的比特位置為1
  2. 添加sigqueue節(jié)點(diǎn)到sigqueue隊(duì)列當(dāng)中,,但是,在添加sigqueue節(jié)點(diǎn)的時(shí)候,,隊(duì)列當(dāng)中已然有了該信號(hào)的sigqueue節(jié)點(diǎn),,則不添加

4.2可靠信號(hào)的注冊(cè)

當(dāng)進(jìn)程所受到可靠信號(hào)時(shí):

在sig位圖中更改信號(hào)對(duì)應(yīng)的比特位為1 不論之前sigqueue隊(duì)列中是否存在該信號(hào)的sigqueue節(jié)點(diǎn),都再次添加sigqueue節(jié)點(diǎn)到sigqueue隊(duì)列當(dāng)中去

5.信號(hào)的注銷

5.1非可靠信號(hào)的注銷

信號(hào)對(duì)應(yīng)的比特位從1置為0 將該信號(hào)的sigqueue節(jié)點(diǎn)從sigqueue隊(duì)列當(dāng)中進(jìn)行出隊(duì)操作

5.2可靠信號(hào)的注銷

將該信號(hào)的sigqueue節(jié)點(diǎn)從sigqueue隊(duì)列當(dāng)中進(jìn)行出隊(duì)操作 需要判斷sigqueue隊(duì)列當(dāng)中是否還有相同的sigqueue節(jié)點(diǎn): ①?zèng)]有了:信號(hào)比特位從1置為0 ②還有:不會(huì)更改sig位圖中的比特位

6.信號(hào)阻塞

6.1信號(hào)是怎樣阻塞的,?

圖片

信號(hào)的阻塞,,并不會(huì)干擾信號(hào)的注冊(cè)。信號(hào)能注冊(cè),,但不能被立即處理,, 將block位圖中對(duì)應(yīng)的信號(hào)比特位置為1,,表示阻塞該信號(hào) 進(jìn)程收到該信號(hào),還是一如既往的注冊(cè) 當(dāng)進(jìn)程進(jìn)入到內(nèi)核空間,,準(zhǔn)備返回用戶空間的時(shí)候,,調(diào)用do_signal函數(shù),就不會(huì)立即去處理該信號(hào)了 當(dāng)該信號(hào)不被阻塞后,,就可以進(jìn)行處理了

6.2sigprocmask

函數(shù)原型:int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 參數(shù)解釋:

how,,該做什么樣的操作
SIG_BLOCK:設(shè)置信號(hào)為阻塞
SIG_UNBLOCK:解除信號(hào)阻塞
SIG_SETMASK:替換阻塞位圖
set:用來(lái)設(shè)置阻塞位圖
SIG_BLOCK:設(shè)置某個(gè)信號(hào)為阻塞,block(new) = block(old) | set
SIG_UNBLOCK:解除某個(gè)信號(hào)阻塞,,block(new)= block(old) & (~set
SIG_SETMASK:替換阻塞位圖,block(new)= set
oldset:原來(lái)的阻塞位圖

例:下述例子,,信號(hào)全部被阻塞,,采用kill -9,將該進(jìn)程結(jié)束掉

#include <stdio.h>
#include <signal.h>
#include <unistd.h>


void signcallback(int signumber)
{
  printf('change the signal %d\n',signumber);
}

int main()
{
  sigset_t set;
  sigset_t oldset;
  sigfillset(&set);//所有比特位全置為1,,則信號(hào)全部會(huì)被阻塞
  sigprocmask(SIG_BLOCK,&set,&oldset);
  while(1)
  {
    sleep(1);
  }

  return 0;
}

結(jié)果: 此時(shí)發(fā)送信號(hào)是不會(huì)有作用的,,采用kill -9強(qiáng)殺掉

圖片

7.信號(hào)未決

7.1 未決概念

實(shí)際執(zhí)行信號(hào)的處理動(dòng)作稱為信號(hào)遞達(dá)(Delivery),信號(hào)從產(chǎn)生到遞達(dá)之間的狀態(tài),,稱為信號(hào)未決(Pending),。 進(jìn)程可以選擇阻塞(Block)某個(gè)信號(hào)。被阻塞的信號(hào)產(chǎn)生時(shí)將保持在未決狀態(tài),,直到進(jìn)程解除對(duì)此信號(hào)的阻塞,,才執(zhí)行遞達(dá)的動(dòng)作。注意,,阻塞和忽略是不同的,,只要信號(hào)被阻塞就不會(huì)遞達(dá),而忽略是,、在遞達(dá)之后可選的一種處理動(dòng)作,。

7.2 sigpending

函數(shù)原型:int sigpending(sigset_t *set); 讀取當(dāng)前進(jìn)程的未決信號(hào)集,通過(guò)set參數(shù)傳出,。調(diào)用成功返回0,,出錯(cuò)返回-1.

例:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void signalcallback(int signumber)
{
  printf('chang signumber %d\n',signumber);
}
void printsigset(sigset_t *set)
{
  int i = 0;
  for(;i < 32;i++)
  {
    if(sigismember(set,i))
    {
      putchar('1');
    }
    else{
      putchar('0');
    }
  }
}

int main()
{
  signal(2,signalcallback);
  signal(10,signalcallback);
  sigset_t set;
  sigset_t oldset;
  sigset_t pending;
  sigfillset(&set);//所有比特位全部置為1,則信號(hào)會(huì)全部被阻塞
  sigprocmask(SIG_BLOCK,&set,&oldset);
  while(1)
  {
    sigpending(&pending);
    printsigset(&pending);
    sleep(1);
  }

  return 0;
}

結(jié)果:圖片

8.信號(hào)的處理方式

圖片
每個(gè)信號(hào)都有兩個(gè)標(biāo)志位分別表示阻塞和未決,,還有一個(gè)函數(shù)指針表示處理動(dòng)作,。

在上述例子中:

  1. SIGHUP信號(hào)未阻塞也未產(chǎn)生過(guò),當(dāng)它遞達(dá)時(shí)執(zhí)行默認(rèn)處理動(dòng)作,。
  2. SIGINT信號(hào)產(chǎn)生過(guò),,但正在被阻塞,所以暫時(shí)不能遞達(dá),。雖然它的處理動(dòng)作是忽略,,但在沒(méi)有解除阻塞之前不能忽略這個(gè)信號(hào),,因?yàn)檫M(jìn)程仍有機(jī)會(huì)改變處理動(dòng)作之后再解除阻塞。
  3. SIGQUIT信號(hào)未產(chǎn)生過(guò),,一旦產(chǎn)生SIGQUIT信號(hào)將被阻塞,,它的處理動(dòng)作是用戶自定義函數(shù)sighandler。

8.1signal函數(shù)

該函數(shù)可以更改信號(hào)的處理動(dòng)作,。

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
參數(shù)解釋:

signum:更改的信號(hào)值
handler:函數(shù)指針,,要更改的動(dòng)作是什么

實(shí)際上,該函數(shù)內(nèi)部也調(diào)用了sigaction函數(shù),。

8.2sigaction函數(shù)

讀取和修改與指定信號(hào)相關(guān)聯(lián)的處理動(dòng)作,。

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

參數(shù)解釋:

signum:待更改的信號(hào)值

struct sigaction結(jié)構(gòu)體:

void     (*sa_handler)(int);//函數(shù)指針,保存了內(nèi)核對(duì)信號(hào)的處理方式
void     (*sa_sigaction)(intsiginfo_t *, void *);//
sigset_t   sa_mask;//保存的是當(dāng)進(jìn)程在處理信號(hào)的時(shí)候,,收到的信號(hào)
int        sa_flags;//SA_SIGINFO,,OS在處理信號(hào)的時(shí)候,調(diào)用的就是sa_sigaction函數(shù)指針當(dāng)中
//保存的值0,,在處理信號(hào)的時(shí)候,,調(diào)用sa_handler保存的函數(shù)
void     (*sa_restorer)(void);

例:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void signcallback(int signumber)
{
  printf('change signumber %d\n',signumber);
}


int main()
{
  struct sigaction act;//act為入?yún)?/span>
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  act.sa_handler = signcallback;

  struct sigaction oldact;//oldact為出參
  sigaction(3,&act,&oldact);
  while(1)
  {
    sleep(1);
  }
  return 0;
}

結(jié)果:圖片

8.3 自定義信號(hào)處理的流程

圖片
  1. task_struct結(jié)構(gòu)體中有一個(gè)struct sighand_struct結(jié)構(gòu)體。
  2. struct sighand_struct結(jié)構(gòu)體有一個(gè)**struct k_sigaction action[_NSIG]**結(jié)構(gòu)體數(shù)組,。
  3. 該數(shù)組中,,其中的**_sighandler_t sa_handler**保存的是信號(hào)的處理方式,通過(guò)改變其指向,,可以實(shí)現(xiàn)我們對(duì)自定義信號(hào)的處理,。

9.信號(hào)的捕捉

9.1信號(hào)捕捉的條件

如果信號(hào)的處理動(dòng)作是用戶自定義函數(shù),在信號(hào)遞達(dá)時(shí)就調(diào)用這個(gè)函數(shù),,這就稱為信號(hào)捕捉,。

9.2信號(hào)捕捉流程

圖片

內(nèi)核態(tài)返回用戶態(tài)會(huì)調(diào)用do_signal函數(shù),兩種情況:

  1. 無(wú)信號(hào):sys_return函數(shù),,返回用戶態(tài)

  2. 有信號(hào):先處理信號(hào),,信號(hào)返回,再調(diào)用do_signal函數(shù) 例:

  3. 程序注冊(cè)了SIGQUIT信號(hào)的處理函數(shù)sighandler,。

  4. 當(dāng)前正在執(zhí)行main函數(shù),,這時(shí)發(fā)生中斷或異常切換到內(nèi)核態(tài)。

  5. 在中斷處理完畢后要返回用戶態(tài)的main函數(shù)之前檢查到有信號(hào)SIGQUIT遞達(dá),。

  6. 內(nèi)核決定返回用戶態(tài)后不是恢復(fù)main函數(shù)的上下文繼續(xù)執(zhí)行,,而是執(zhí)行sighandler函數(shù), sighandler和main函數(shù)使用不同的堆??臻g,,它們之間不存在調(diào)用和被調(diào)用的關(guān)系,是兩個(gè)獨(dú)立的控制流程,。

  7. sighandler函數(shù)返回后自動(dòng)執(zhí)行特殊的系統(tǒng)調(diào)用sigreturn再次進(jìn)入內(nèi)核態(tài),。

  8. 如果沒(méi)有新的信號(hào)要遞達(dá),,這次再返回用戶態(tài)就是恢復(fù)main函數(shù)的上下文繼續(xù)執(zhí)行了。

10.常用信號(hào)集操作函數(shù)

int sigemptyset(sigset_t *set);://將比特位圖全置為0

int sigfillset(sigset_t *set);//將比特位圖全置為1

int sigaddset(sigset_t *setint signum);//將該set位圖,,多少號(hào)信號(hào)置為1

int sigdelset(sigset_t *setint signum);//將該set位圖,,多少號(hào)信號(hào)置為0

int sigismember(const sigset_t *setint signum);//信號(hào)signum是否是set位圖中的信號(hào)

11.SIGCHLD信號(hào)

該信號(hào)是子進(jìn)程在結(jié)束是發(fā)送給父進(jìn)程的信號(hào),但是該信號(hào)的處理方式是默認(rèn)處理的,。 父進(jìn)程對(duì)子進(jìn)程發(fā)送過(guò)來(lái)的SIGCHLD信號(hào)進(jìn)行了忽略處理,,就會(huì)導(dǎo)致子進(jìn)程成為僵尸進(jìn)程。

可以自定義該信號(hào)的處理方式:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>

void signcallback(int signumber)
{
  printf('change signal %d\n',signumber);
  wait(NULL);
}

int main()
{
  signal(17,signcallback);
  pid_t pid = fork();
  if(pid < 0)
  {
    perror('fork');
    return -1;
  }
  else if(pid == 0)
  {
    printf('I am child\n');
    sleep(1);
    exit(12);
  }
  else{
    while(1)
    {
      sleep(1);
    }
  }
  return 0;
}


指令查看后臺(tái):ps aux | grep ./fork

圖片

原文地址: 

https://blog.csdn.net/w903414/article/details/109802539?utm_source=app&app_version=4.18.0&utm_source=app

end


一口Linux 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多