信号的机制
进程A给进程B发送信号,进程B收到信号之前执行自己的代码,收到信号后,不管执行到程序的什么位置,都要暂停运行,去处理信号。处理完毕以后再继续执行,与硬件中断类似(软中断),每个进程收到的所有信号,都是由内湖负责发送的。
信号的处理方式
- 执行默认动作
- 忽略信号(丢弃不处理)
- 捕捉信号(调用用户的自定义的处理函数)
信号相关函数
signal函数:
- 作用:注册信号捕捉(处理)函数
- 函数原型
- typedef void(*sighandler t)(int);
- sighandler_t signal(int signum,sighandler_t handler);
- 函数参数
- signum:信号编号
- handler:信号处理函数
- 信号四要素:(man)
- 编号
- 名字
- 默认处理动作
- 信号是如何产生的
给一个没有读端的管道写数据,会产生SIGPIPE信号。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/types.h>
5 #include<unistd.h>
6 #include<sys/wait.h>
7
8 //信号处理函数
9 void sighandler(int signo){
10 printf("signo==[%d]\n",signo);
11 }
12
13
14 int main()
15 {
16 //创建管道
17 //int pipe(int pipefd[2])
18 int fd[2];
19 int ret = pipe(fd);
20 if(ret<0)
21 {
22 perror("pipe error");
23 return -1;
24 }
25
26 //注册SIGPIPE信号处理函数
27 signal(SIGPIPE,sighandler);
28
29 //关闭读端
30 closed(fd[0]);
31
32 write(fd[1],"hello world",strlen("hello world"));
33
34 return 0;
35 }
kill函数/命令
- 描述:给指定进程发送指定信号
- kill命令:kill -SIGKILL 进程PID
- kill函数原型:int kill(pid_t pid,int sig);
- 返回值: 成功:0,失败 -1
- 函数参数
- sig信号参数:不推荐直接使用数字,应使用宏名,因为不同操作系统信号编号可能不同,但名称一致。
- pid参数:
- pid>0:发送信号给指定的进程(基本只用这一个)
- pid=0:发送信号给与调用kill函数进程属于同一进程组的所有进程
- pid<-1:取|pid|发给对应进程组
- pid=-1:发送给进程有权限发送的系统中所有进程。
abort函数raise函数:
- raise函数
- 函数描述:当前进程给自己发送信号
- 函数原型:int raise(int sig);
- 返回值:0成功。失败非0
- 函数拓展:raise(signo) == kill(getpid(),signo);
- abort函数
- 函数描述:给自己发送终止信号,6)SIGABRT 并产生core文件
- 函数原型:void abort(void);
- 函数拓展:abort() = kill(getpid(),SIGABRT);
alam函数
- 函数原型:unsigned int alarm(unsigned int seconds);
- 函数描述:设置定时器。在指定seconds后,内核会给当前进程发送(14)SIGALRM信号。进程收到该信号,默认动作为终止。每个进程有且都有唯一的一个定时器
- 函数返回值:返回0或剩余的秒数,无失败。
- 常用操作:取消定时器alarm(0),返回旧闹钟余下秒数。
alarm使用的是自然定时法,与进程状态无关,就绪、运行、挂起(阻塞、暂停)、终止、僵尸...无论进程处于何种状态,alarm都计时。
//测试alarm函数。
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/types.h>
5 #include<unistd.h>
6 #include<signal.h>
7
8
9 void sighandler(int signo){
10 printf("signo==[%d]\n",signo);
11 }
12
13 int main()
14 {
15
16 signal(SIGALRM,sighandler);
17
18 int n =alarm(5);
19 printf("n==[%d]\n",n);
20
21 sleep(2);
22 n = alarm(1);
23 printf("n==[%d]\n",n);
24 sleep(10);
25
26 return 0;
27
28 }
测试电脑1秒钟能写多少个数
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/types.h>
5 #include<unistd.h>
6 #include<signal.h>
7
8 int main()
9 {
10 alarm(1);
11 int i =0;
12 while(1)
13 {
14 printf("[%d] ",i++);
15 }
16 return 0;
17 }
~
setitimer函数
- 函数原型
-
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
-
- 函数描述
-
设置定时器(闹钟),可代替alarm函数,精度微秒us,可以实现周期定时。
-
- 函数返回值
- 成功:0;
- 失败:-1,设置errno值
- 函数参数:
- which:指定定时方式
- 自然定时:ITIMER_REAL → 14)SIGALRM计算自然时间
- 虚拟空间计时(用户空间):ITIMER_VIRTUAL → 26)SIGVTALRM 只计算进程占用cpu的时间
- 运行时计时(用户+内核):ITIMER_PROF → 27)SIGPROF计算占用cpu及执行系统调用的时间
- new_value:struct itimerval, 负责设定timeout时间。
- itimerval.it_value: 设定第一次执行function所延迟的秒数
- itimerval.it_interval: 设定以后每几秒执行function
- which:指定定时方式
- old_value: 存放旧的timeout值,一般指定为NULL
-
struct itimerval {
struct timerval it_interval; // 闹钟触发周期
struct timerval it_value; // 闹钟触发时间
};
struct timeval {
long tv_sec; // 秒
long tv_usec; // 微秒
}
setitimer练习
//setitimer练习
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #include<sys/types.h>
5 #include<unistd.h>
6 #include<signal.h>
7 #include<sys/time.h>
8
9 void sighandler(int signo)
10 {
11 printf("signo==[%d]\n",signo);
12 }
13
14 int main()
15 {
16
17 //注册SIGALRM信号处理函数
18 signal(SIGALRM,sighandler);
19
20 struct itimerval tm;
21 //周期性时间赋值
22 tm.it_interval.tv_sec = 1;
23 tm.it_interval.tv_usec = 0;
24 //第一次触发的时间
25 tm.it_value.tv_sec =3;
26 tm.it_value.tv_usec = 0;
27
28 setitimer(ITIMER_REAL,&tm,NULL);
29
30
31 while(1)
32 {
33 sleep(1);
34 }
35 return 0;
36 }
~
~