信号通信,其实就是内核向用户空间进程发送信号,只有内核才能发信号,用户空间进程不能发送信号。
内核可以发送多少种信号呢?
通过命令kill -l
命令:kill -9 pid
通过命令查看到有64种信号
信号通信的框架
1、信号的发送(发送信号进程):kill raise alarm
2、信号的接收(接收信号进程) : pause() sleep while(1)
3、信号的处理(接收信号进程) : signal
- 信号的发送(发送信号进程)
kill :
kill命令的程序实现实例
raise函数(相当于exit函数)
raise函数例子
alarm : 发送闹钟信号的函数:
alarm 与 raise 函数的比较:
相同点:让内核发送信号给当前进程
不同点:
- alarm 只会发送SIGALARM信号
- alarm 会让内核定时一段时间之后发送信号, raise会让内核立刻发信号
- 信号的接收(接收信号进程)
接收信号的进程,要有什么条件:要想使接收的进程能收到信号,这个进程不能结束 :
sleep
pause:进程状态为S
while(1)
pause函数
通过查看进程可以看到此时进程为sleep
3.信号的处理(接收信号进程)
收到信号的进程,应该怎样处理? 处理的方式:
(1) 进程的默认处理方式(内核为用户进程设置的默认处理方式)
A:忽略
B:终止进程
C: 暂停
(2) 自己的处理方式:
自己处理信号的方法告诉内核,这样你的进程收到了这个信号就会采用你自己的的处理方式
函数原型void (*signal(int signum, void (*handler)(int)))(int);
void (*handler)(int) 相当于函数指针变量,函数的形式:含有一个整形参数,无返回值
A=void (*handler)(int)
相当于void (*signal(int signum, A(int);
其中
SIG_IGN:(ignore忽略)忽略该信号。
SIG_DFL:(default)采用系统默认方式处理信号。
自定义信号处理:先处理A,后处理B进程
signal 函数有二个参数,第一个参数是一个整形变量(信号值),第二个参数是一个函数指针,是我们自己写的处理函数;
这个函数的返回值是一个函数指针。
signal函数的例子
可以看出,程序进入main函数运行9秒后进入睡眠,进入signal函数进行处理,处理完后再运行main函数处理
所以简单来说signal(告诉内核处理哪一个参数,采用说明方式去处理(1、忽略2、默认3、自己定义的函数))
下面是第一种处理方式:SIG_IGN
一样的函数,我们进行了忽略处理,所以结果没有运行myfun函数
第二种SIG_DFL
9秒以后收到信号,默认终止
练习:有二个进程,一个server.c 一个client.c,要求server.c负责创建有名管道文件,即server要先运行,client后运行。
对父子进程进行处理
这里对父子进程进行操作,父进程开始打印,打印10个以后,signal得到信号,对myfun函数进行操作,myfun打印完后回到main函数,父进程继续操作,当打印14个以后,signal的17号是SIGCHLD,进行signal的myfun1操作,myfun1是对僵尸进程的回收,其中wait函数是对僵尸进程的回收,运行完myfun1以后,继续运行main函数