一、概念:
信号是UNIX系统响应某些状况而产生的事件,进程在接收到信号时会采取相应的行动。
信号是因为某些错误条件而产生的,比如内存段冲突、浮点处理器错误或者非法指令等。
1、分类:分为软中断和硬中断产生的信号,其中软中断实际为借助硬件手段完成。
2、特点
1)简单;2)不能携带大量信息;3)满足某个条件才发送。
3、特质
由于信号通过软件方法实现,具有很强延时性对用户来讲,时间非常短,不易察觉。
4、每个进程收到的所有信号,都由内核负责发送,由内核处理。
二、与信号相关的事件或名词
1、产生信号的基本方法
1)系统调用当前进程的执行函数(kill)
2)通过命令产生 kill
3)硬件异常,段错误:内存出错;总线出错。
4)软件条件产生(alarm,定时器)
5)按键测试的(ctrl+c)
三、信号的处理方法
1、默认动作 例如:ctrl+c将进程杀死
如:终止进程、终止进程并且产生core文件(用于调试)、忽略、暂停、继续等
2、忽略(丢弃) 信号处理完,把信号丢弃,不在未决集里
3、信号捕捉 ,不去执行默认动作
//程序1 执行程序杀死当前进程
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
//man 2 kill 查看头文件
int main()
{
int ret;
ret=kill(getpid(),SIGKILL);//把参数SIGKILL信号发送给当前进程。
if(ret==-1)//调用失败
{
exit(1);
}
return 0;
}
程序执行效果:
//程序2 创建5个子进程,杀死其中第三个子进程
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define N 5
int main()
{
int i;//普通变量
pid_t pid,q;//进程返回值
for(i=0;i<N;i++)
{
pid=fork();//创建进程
if(pid==0)//子进程
{
break;
}
if(i==2)
{
q=pid;
}
}
if(i<N)
{
while(1)
{
printf("I am the child %d,pid=%d\n",i,getpid());
sleep(1);
}
}
else
{
kill(q,SIGKILL);//杀死第q个进程
}
return 0;
}
四、定时器
1、每个进程只有唯一一个定时器。
2、无论进程处于何种状态(运行,就绪,僵尸,终止)下,都在计时
3、功能:设置一个闹钟,发送alarm信号
4、返回值:返回之前剩余的信号。
5、time 命令:用于查看程序执行时间,实际时间=系统时间+用户时间+等待时间
6、setitimer 周期性定时,微秒
1)计算自然时间14
2)只计算进程占用CPU的时间 25
3)计算占用CPU及系统调用的时间26
结构体struct itimerval,成员:
1)it_value:设定触发时间。
2)it_interval:设定触发周期。
1)、2)均有(int)tv_sec,(int)tv_usec的结构体成员。
补充:
进程A产生信号,通过内核马上送到进程B
阻塞信号集:即信号屏蔽字
未决信号集:没有被处理掉的信号集合
kill -l //查看当前所有的信号
//程序3-1 计算计算机1s能数多少个数(法一)
#include <unistd.h>
#include <stdio.h>
//time ./count1 --显示具体执行时间
int main(void)
{
int i;
alarm(1);//定时1s
for(i=0;;i++)
{
printf("%d\n",i);//显示数字
}
return 0;
}
//程序3-2 计算计算机1s能数多少个数(法二)
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
//定时函数定义
unsigned int myalarm(unsigned int sec)
{
struct itimerval it,oldit;
int ret;
it.it_value.tv_sec=sec;//设定触发时间
it.it_value.tv_usec=0;
it.it_interval.tv_sec=sec;//设定触发周期
it.it_interval.tv_usec=0;
ret=setitimer(ITIMER_REAL,&it,&oldit);//定时
if(ret==-1)
{
exit(1);
}
return oldit.it_value.tv_sec;
}
//主函数
int main(void)
{
int i;
myalarm(1);//调用定时函数
for(i=0;;i++)
{
printf("%d\n",i);//输出数字
}
return 0;
}
程序执行效果:
//程序4 将捕捉到的信号用定时方式输出
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>
void myfun(int signo)//输出hello world
{
printf("hello world\n");
}
void myfun2(int signo)
{
printf("close error\n");
}
int main(void)
{
struct itimerval it,oldit;//定义结构体类型变量
//捕捉的信号
signal(SIGALRM,myfun);
//屏蔽ctrl+c
//signal(SIGINT,myfun2);
int ret;
it.it_value.tv_sec=5;//5s触发一次
it.it_value.tv_usec=0;
it.it_interval.tv_sec=3;//3s的间隔
it.it_interval.tv_usec=0;
ret=setitimer(ITIMER_REAL,&it,&oldit);//设置定时
if(ret==-1)
{
printf("settimer error");
exit(1);
}
for(;;);//让程序持续执行
return 0;
}
程序执行效果:
//程序5 输出当前进程未决信号集,及测试屏蔽信号
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
//显示函数定义
void printfped(sigset_t *ped)
{
int i;
for(i=0;i<32;i++)
{
if(sigismember(ped, i)==1)//判断信号是否存在信号集中,'1'为存在
{
putchar('1');//输出1
}
else
{
putchar('0');//输出0
}
}
printf("\n");
sleep(1);
}
//主函数
int main(void)
{
//自定义集合,影响pcb,阻塞信号集
sigset_t myset,oldset,ped_set;
sigemptyset(&myset);//清空自定义信号集
//sigaddset(&myset,SIGQUIT);//设置ctrl+/信号(3)
sigaddset(&myset,SIGINT);//设置ctrl+c信号(2)
sigaddset(&myset,SIGTSTP);//设置ctrl+z信号(19)
sigprocmask(SIG_BLOCK,&myset, &oldset);//读取或更改进程的信号屏蔽字
//查看未决信号集
while(1)
{
sigpending(&ped_set);
//显示
printfped(&ped_set);
}
return 0;
}
程序执行效果: