#用alarm函数发送信号
进程可以通过调用alarm函数向它自己发送SIGALRM信号
例子1:
#include "csapp.h"
int beeps = 0; //定义全局变量beeps并赋初值0,用于计数
/* SIGALRM handler */
void handler(int sig) { //信号处理程序handler,入口参数为整型的信号编号,无返回值
sio_puts("BEEP\n"); //调用系统io函数sio_puts输出BEEP
if (++beeps < 5)//++为前缀运算符,beeps先加1,后与5比较。这里共4次满足条件
alarm(1);//一秒钟之后,向调用进程发送SIGALRM信号
else { //第五次收到信号时
sio_puts("BOOM!\n"); //调用系统io函数sio_puts输出BOOM
_exit(0); //不清空输出缓冲区,直接退出,进程终止
}
}
int main() {
signal(SIGALRM, handler); //一旦接受到信号SIGALRM(来自alarm的定时器信号),就转而去执行handler程序
alarm(1);//一秒钟之后,向调用进程发送SIGALRM信号
while (1) { //进程不断执行while死循环(直到接收到SIGALRM信号)
continue; //信号处理程序handler前四次返回此处
}
}
该程序执行时,进程调用alarm函数向自己一共发送了5次SIGALRM信号,从而5次执行了信号处理程序handler,输出5次BEEP。最后一次调用handler函数时,因为计数条件限制,执行else语句,输出BOOM!,并退出调用进程。
程序运行结果如下:
#signal函数用于接收信号,并将控制转移到信号处理程序
sleep函数用于使调用进程休眠(从而让别的进程先执行),即将一个进程挂起一段指定的时间
这里关于typedef的使用参考了链接https://blog.csdn.net/davidsky11/article/details/28278973
#include <signal.h>
typedef void (*sighandler_t)(int);//将sighandler_t定义为一个指针类型(该指针用于指向返回值为void型,入口参数为int型的函数)
sighandler_t signal(int signum, sighandler_t handler);//入口参数signum为信号名称,handler为某个信号处理程序,若成功则返回前次处理程序的指针,若出错则为 SIG_ERR
#include <unistd.h>
unsigned int sleep(unsigned int secs);//入口参数secs为无符号整型,表示要求休眠的秒数;返回值为无符号整型,表示还要休眠的秒数
例子:
int ccount = 0;
void child_handler(int sig)//入口参数为信号编号,无返回值(该函数作用是回收终止的子进程,并输出相关提示信息)
{
int child_status;//用于存储子进程退出状态
pid_t pid = wait(&child_status);//回收终止的子进程,返回其pid,并将子进程退出状态存入child_status
ccount--;//全局变量ccount减一,表示待回收的子进程数目减一
printf("Received SIGCHLD signal %d for process %d\n", sig, pid); /* Unsafe *///输出收到来自哪个子进程的终止信号
fflush(stdout); /* Unsafe *///清空输出缓冲区
}
/*
* fork14 - Signal funkiness: Pending signals are not queued
*/
void fork14()
{
pid_t pid[N];//定义pid数组用于在父进程中存储子进程的Pid
int i;
ccount = N;//将全局变量赋值为N(N==5)
signal(SIGCHLD, child_handler);//一旦接收到子进程终止信号SIGCHLD,就转而执行信号处理程序child_handler
for (i = 0; i < N; i++) {//循环5次,共创建5个子进程
if ((pid[i] = fork()) == 0) {//父进程中,将子进程PID依次存入pid数组
sleep(1);//子进程休眠1s
exit(0); /* Child: Exit *///子进程终止,并向父进程发送一个SIGCHLD信号
}
}
while (ccount > 0)//直到子进程全部回收完,父进程才会跳出while循环
;
}
本程序的sleep(1)使得子进程休眠了1s,这直接使得子进程最终只被回收了1个或2个(控制默认总是在父进程)。将源程序中sleep(1)删掉,或在while循环里调用sleep函数(使父进程休眠),可以看到回收多个子进程的情况。
运行结果:
删去源程序中的sleep(1),并在while循环里调用sleep(5)后的运行结果:
这里接收到信号的顺序是不确定的。