一.信号通信
引入:
思考:
A让内核发送信号给B
1.A需要告诉内核发给谁
2.A需要告诉内核发送什么信号给B?
$ 信号通信的框架
- 信号的发送(发送信号进程,信号的发送相关的函数)
kill alarm raise
函数;其实就是A发送信号给内核对象 - 信号的接收(接收信号进程)
pause sleep while()
;其实就是B接收内核发送的信号 - 信号的处理;其实就是B接收到内核的信号之后怎么处理
1.信号的发送
(1)kill
kill函数是系统调用函数。
作用:给指定进程发送指定信号。(不一定会杀死进程,取决于发送的是什么信号)
利用kill
函数可以实现kill
命令。
补充知识:kill
命令
Kill命令其实是用来发送信号的,我们常用的Kill -9 pid
只是给某个进程发送9号信号而已,而不是说杀死该进程。
kill 9 5741
9(必杀信号)是信号类型 ,5741是test的PID号
将必杀信号发送给5741,会导致杀死5741进程
(2)raise:发信号给自己 ==kill(getpid() , sig)
eg:
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "fcntl.h"
int main()
{
printf("raise before\n");
raise(9);//此条语句终止本身进程
printf("raise after\n");//此条语句不会显示
return 0;
}
例子:
//加深对kill和raise的理解
#include "stdio.h"
#include "unistd.h"
#include "stdlib.h"
#include "fcntl.h"
int main()
{
pid t pid;
pid=fork();
if(pid >0)
{
sleep(8);//这个时候父进程处于睡眠S状态
//8s之后父进程进入运行R状态
//补充:阻塞和非阻塞很简单,将waitpid设置为阻塞后如果子进程没有退出,那么父进程就会一直等待,直到子进程退出。
//父进程查看子进程状态,子进程没有退出,父进程立即返回去执行其它任务,这一次的过程叫做非阻塞。(而父进程多次来回确认子进程有没有退出的过程称为轮询)
//如果将WNOHANG非阻塞变为0阻塞,那么kill(pid,9)不会执行,父进程变为阻塞状态
if(waitpid(pid,NULL,WNOHANG) == 0)
{
kill(pid,9);//杀死pid子进程
}
//wait(NULL);//wait会回收子进程资源
while(1);//子进程处于死循环状态,没有为子进程回收资源,子进程会变为僵尸Z状态
}
if(pid =0)
{
printf("raise function before\n");
raise(SIGTSTP);//子进程会处于暂停T状态
printf("raise funtion after\n");
exit(0);
}
return 0;
}
(3)alarm函数:只会发送闹钟SIGALRM信号
- 调用alarm函数内核不会立马发出信号,而是当定时时间到只会才会发出alarm信号,内核发送的信号也只能给当前进程,收到alarm信号之后进程终止。
- alarm函数不需要告诉内核发送什么信号,因为它只能发送闹钟函数,但是需要告诉内核延时多久发送。
eg:
#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
int i;
i=0;
printf("alarm before\n");
alarm(9);
printf("alarm after\n");
while(i<20)//在收到alarm信号之前进程不能终止
{
i++;
sleep(1);
printf("process things \n");
return 0;
}
}
2.信号的接收
接收信号的进程,要有什么条件:要想使接收的进程能收到信号,这个进程不能结束:
sleep:睡眠一段时间
while(1)
pause:进程状态为S睡眠状态,pause一直处于运行,即让进程一直处于s状态
#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
int i;
i=0;
printf("pause before \n");
pause();//pause在此处s睡眠
printf("pause after\n");
while(i<20)
{
i++;
sleep(1);
printf("process things,i=%d\n",i);
return 0;
}
}
3.信号的处理
- 前面已经涉及到信号的处理,(默认处理方式)比如收到alarm、SIGSTP信号等,默认终止进程。
- 进程通信实际的用的较多的是:A发送信号给B,B进行信号的处理之后,再回来处理自己的进程,此时涉及到一个重要函数SIGNAL()。
- signal函数:
作用:告诉内核处理哪个信号,告诉内核怎么处理信号(采用何种方式处理:忽视;默认处理方式(一般是终止);采用自己的函数去处理)自定义的信号处理函数指针:先进入处理函数,处理完之后回到B处理的事情。
eg:
#include "stdio.h"
#include "sys/types.h"
#include "signal.h"
#include "stdio.h"
#include "stdlib.h"
void myfun(int signum)
{
int i;
i=0;
while(i<10)
{
printf("process signal signum=%d\n",signum);
sleep(1);
1++;
}
return;//return main
}
int main()
{
int i;
i=0;
//signal(14,SIG_IGN);//忽视当前信号
//signal(14,SIG_DFL);//默认处理方式 终止当前进程
signal(14,myfun);//接收到14信号之后会处理myfun函数内容,myfun函数处理完之后会继续接着处理while里面的内容
printf("alarm before\n");
alarm(9);
printf("alarm after\n");
while(i<20)
{
i++;
sleep(1);
printf("process things,i=d\n",i);
return 0;
}
}
函数运行结果: