信号
-
信号机制:进程B发给进程A,内核产生信号,内核处理
-
信号的产生:
- 按键产生:CTRL+c,CTRL+z。。。
- 调用函数:kill。。。。
- 定时器:alarm
- 命令:kill
- 硬件异常;段错误,浮点型错误,总线错误
-
信号的状态:
- 产生
- 递达 信号到达且处理完
- 未决 信号阻塞
-
信号的默认处理方式
- 忽略
- 执行默认动作
- 捕获
-
信号的四要素
- 编号
- 事件
- 名称
- 默认处理动作:
- 忽略
- 终止
- 终止+core
- 暂停
- 继续
-
系统api:kill
- 头文件:
#include <sys/types>
#include <signal.h>
- 函数:
kill(pid_t pid, sig)
- pid是要kill的进程
- sig传入的信号,SIGKILL就是杀死进程
- 头文件:
-
系统api:raise
- 头文件:
#include <signal.h>
- 函数:
void raise(sig)
,对自己操作,相当于kill(getpid(),sig)
- 头文件:
-
系统api:abort
- 头文件:
#include <stdlib.h>
- 函数:
void abort();
,异常退出
- 头文件:
-
系统api:alarm
- 头文件:
#include <stdlib.h>
- 函数:
unsigned int alram(unsigned int seconds);
- 在seconds后,内核会给进程发送14)SIGALRM信号。进程收到该信号,默认动作终止
- 返回0或剩余的秒数,五失败
- 如果传入参数为0,代表取消闹钟
- 一个进程只有一个alarm
- 头文件:
-
系统api:setitimer
-
头文件:
#include <sys/time.h>
-
函数:
int setitimer(int which, const struct itimerval *new_value, const struct itimerval *old_value);
-
which:
- ITIMER_REAL : 对应信号SIGALRM,(常用),自然定时时间
- ITIMER_VIRTUAL : 对应信号SIGVTALRM,计算进程执行时间
- ITIMER_PROF : 对应信号是SIGPROF,进程执行时间+调度时间
-
new_value :
-
old_value :
-
结构体
-
struct itimerval{ struct timerval it_interval;//周期时间设置 struct timerval it_value;//下次的闹钟时间 } struct timeval{ time_t tv_sec ;/秒 suseconds_t tv_usec; //纳秒 }
-
-
-
例子
-
#include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <signal.h> //捕获信号 void catch_sig(int num){ printf("cat %d sig",num); } int main() { signal(SIGALRM,catch_sig);//先设定信号 struct itmerval myit = {{3,0},{5,0}};//第一个周期是5秒,后面周期是3s settimer(ITIMER_REAL,&myit,NULL); while(1){ printf("kill me!\n"); sleep(1); } }
-
信号捕捉:防止进程意外死亡
-
typedef void(*sighandle_t)(int)
e.g.void catch_sig(int num)
-
注册捕捉函数:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
-
signum 捕捉的信号
-
act 传入的动作
-
oldact 原动作,恢复现场
-
struct sigaction{ void (*sa_handler)(int);//函数指针 void (*sa_sigaction)(int, sigaction_t *,void *); sigset_t sa_mask;//在执行捕捉函数期间,临时屏蔽的信号集 int sa_flags;//一般填0 void (*sa_restorer)(void);//无效 }
-
往sa_mask添加临时屏蔽信号:
sigaddset(&sa_mask,SIGQUIT);
只生效一次e.g.
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/time.h> void catch_sig(int num) { printf("catch %d sig\n",num); } int main() { //注册捕捉函数 struct sigaction act; act.sa_flags = 0; act.sa_handler = catch_sig; sigemptyset(&act,sa_,mask);//清空 sigaction(SIGALRM,&act,NULL); //setitimer strucr setitimer myit = {{3,0},{5,0}}; setitimer(ITIMER_REAL,&myit,NULL); while(1){ printf("kill me\n"); sleep(1); } return 0; }
-
-
捕捉特性
- 某信号捕捉函数执行期间,某信号自动被屏蔽
- 阻塞的常规信号不支持排队,产生多次只记录一次
-
-
SIGCHLD
-
子进程在暂停或者退出的时候会发送SIGCHLD信号,可以通过捕捉SIGCHLD来回收子进程
-
#include <stdio.h> #include <unistd.h> #inclued <sys/types.h> #include <signal.h> void catch_sig(int num){ pid_t wpid; while((wpid = waitpid(-1,NULL,WNOHANG))>0){ printf("child %d ok\n",wpid); } } int main() { int i = 0; pid_t pid; for(int i 0;i<10;i++){ pid = fork(); if(pid == 0){ break; } } //在子进程死之前屏蔽信号 sigset_t myset,oldset; sigemptyset(&myset); sigaddset(&myset,SIGCHLD);//添加屏蔽信号集 //oldset,保留现场 sigprocmask(SIG_BLOCK,&myset,&oldset); if(i == 10){ struct sigaction act; act.sa_flags = 0; sigemptyset($act.sa_mask); act.sa_handler = catch_sig; sifaction(SIGCHLD,&act,NULL);//注册捕捉函数 //解除屏蔽信号 sigprocmask(SIG_SETMASK,&oldset,NULL); while(1){ sleep(1); } }else if(i<10){ printf("iam child,pid=%d",getpid()); } }
-
为了避免子进程死在注册捕捉函数前成为僵尸进程,可以先屏蔽/忽略
SIGCHLD
信号
-
守护进程
- 创建会话
- 不能是进程组长
- 建立会话时,父进程退出,子进程setsid :
pid_t getdid(pid_t pid);
成功返回进程会话的pid,失败-1,设置errno - 守护进程一般以的结尾:daemon
- 创建守护进程模型
- 创建子进程,父进程退出
- 在子进程中创建会话,
setsid()
- 改变当前目录,
chdir()
- 设置文件权限,
umask()
- 关闭文件描述符,0,1,2,为了避免浪费资源
- 执行守护进程核心
- 守护进程退出
- shell端达到守护进程:
nohup ./a.out >> &
nohup
指令会让cmd接收不到SIGHUP信号&
代表后台运行