1、产生信号
产生信号的3种方式:
1、调用系统函数:kill(); raise(); abort(();
2、软件异常行为;
3、组合键:Ctrl+c Ctrl+d Ctrl+\等;
处理信号的3种方式:
1、忽略。
2、默认(很多情况下是终止)。
3、自定义(信号捕捉)。
信号在内核中的表示:
1、递达:执行信号的处理动作称为信号递达(Delivery)。
2、未决:信号从产生到递达之间的状态,称为信号未决(Pending)。
3、阻塞:进程可以选择阻塞(Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞才执行递达的动作。
注意:阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后 可选的一种处理动作。
信号集操作函数
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void show_pending(sigset_t *set)
{
int i = 1;
for(;i<31;i++){
if(sigismember(set,i))
{
printf("1");
}else{
printf("0");
}
}
printf("\n");
}
int main()
{
sigset_t block,oblock,pending;
sigemptyset(&block);
sigemptyset(&oblock);
sigemptyset(&pending);
sigaddset(&block,2);
sigprocmask(SIG_SETMASK,&block,&oblock);
while(1){
sigpending(&pending);
sleep(1);
show_pending(&pending);
}
return 0;
}
模拟实现Sleep
1、该程序有bug(无保护机制)
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
int count = 0;
void handler(int sig)
{
}
int mysleep(int second)
{
struct sigaction act,oact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);
alarm(second);
pause();
int time = alarm(0);
sigaction(SIGALRM,&oact,NULL);
return time;
}
int main()
{
while(1)
{
printf("hello I am sleping\n");
mysleep(3);
}
return 0;
}
模拟实现Sleep
2、该程序无Bug(有保护机制)
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
int count = 0;
void handler(int sig)
{}
int mysleep(int second)
{
struct sigaction act,oact;
sigset_t nmask,onmask,unmask;
//信号捕捉动作设置
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM,&act,&oact);
//信号屏蔽设置
sigemptyset(&nmask);
sigaddset(&nmask,SIGALRM);
sigprocmask(SIG_BLOCK,&nmask,&onmask);
alarm(second);//设置闹钟
//解除信号屏蔽
unmask = onmask;
sigdelset(&unmask,SIGALRM);
sigsuspend(&unmask);
int time = alarm(0);
sigaction(SIGALRM,&oact,NULL);
return time;
}
int main()
{
while(1)
{
printf("hello I am sleping\n");
mysleep(3);
}
return 0;
}
1. 调用sigprocmask(SIG_BLOCK, &nmask, &omask);时屏蔽SIGALRM。
2. 调用sigsuspend(&unpmask);时解除对SIGALRM的屏蔽,然后挂起等待待。
3. SIGALRM递达后suspend返回,自动恢复原来的屏蔽字,也就是再次屏蔽SIGALRM。
4. 调用sigprocmask(SIG_SETMASK, &oldmask, NULL);时再次解除对SIGALRM的屏蔽。