1. 信号的产生的三种方式
下面简单介绍下kill(2), raise(3), alarm(2)
1.1 kill(2)
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
// C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)。
kill(atoi(argv[2]), atoi(argv[1]));
return 0;
}
- 相当于实现了一个 kill命令
1.2 raise(3)
- raise(3) 应该只是kill(2)的一个简单封装
RAISE(3) Linux Programmer's Manual RAISE(3)
NAME
# 发送一个信号给调用者,也就是当前进程
raise - send a signal to the caller
SYNOPSIS
#include <signal.h>
int raise(int sig);
DESCRIPTION
The raise() function sends a signal to the calling process or thread. In a single-threaded program it is equivalent to
# raise(sig); 相当于 kill(getpid(), sig);
kill(getpid(), sig);
1.3 alarm(2)
-
未决可以先简单理解为未完成。设置了一个闹钟是5秒,结果在3秒的时候闹钟就被废掉了,这个两秒钟就是未决时间值。
-
后面的alarm会把前面的alarm覆盖到,如果后面是alarm(0), 会把前面的alarm取消
-
代码示例
#include <stdio.h>
#include <unistd.h>
int main(void){
alarm(5);
int i = 0;
for(i=1; i<=250000; i++){
printf("%d\n", i);
}
// 取消原来的闹钟, 变量a中存放的是原来闹钟的未决时间值
unsigned int a = alarm(0);
printf("上个闹钟的未决时间值: %u\n", a);
}
$ a.out
1
...
250000
上个闹钟的未决时间值: 4
2. 暂停进程 pause(2)
- pause 会经常和alarm配合使用
- pause(2)的返回值比较奇怪,只有被信号打断的时候才返回。如果没有信号来,那就一直休眠,直到信号到达, 信号到了pause调用信号处理函数,默认是终止进程,具体去了解signal 信号处理函数
- pause在让进程进入睡眠状态之前已经把CPU让出去了,属于挂起等待。等待有两种, 盲等(不让出CPU, CPU一直在消耗),和挂起(把CPU让出去了, CPU该干嘛干嘛)
2.1 使用alarm(2), pause(2)实现sleep(3)的功能
- sleep(3)原型
unsigned int sleep(unsigned int seconds);
t_sleep.c
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
// 信号处理函数, 什么都不做,只是为了不采用默认处理方式
void handle(int n){};
unsigned int t_sleep(unsigned int seconds){
alarm(seconds);
pause(); // 进程对信号忽略了,信号就无法打断pause(2)了
//取消了原来的闹钟, 并返回原来闹钟的未决时间值
return alarm(0);
}
int main(void){
// 不能直接忽略SIGALRM信号, 因为忽略以后,就无法打断pause了
// signal(SIGALARM, handle);
// 调用信号处理函数handle, 什么都不做,只是为了不采用默认处理方式(SIGALARM信号直接将进程结束)
signal(SIGALRM, handle);
while(1){
printf("ni hao ..\n");
t_sleep(2);
}
return 0;
}
$ ./a.out
ni hao ..
ni hao ..
ni hao ..
ni hao ..