Linux进程6-alarm闹钟定时终止、raise发送信号、abort终止、pause挂起进程验证
目录
1.alarm函数
1.1关键点
1.2单个alarm函数定时
1.3两个alarm函数定时
2.raise函数
2.1核心行为
2.2 raise与 kill 的区别
2.3程序:
3.abort函数
4.pause 函数
4.1 pause简单挂起
4.2父进程挂起,子进程发信号
1.alarm函数
函数原型:
#include <unistd.h>unsigned int alarm(unsigned int seconds);功能:定时器,闹钟,当设定的时间到达时,会产生SIGALRM信号参数:seconds:设定的秒数返回值:如果alarm函数之前没有alarm设置,则返回0如果有,则返回上一个alarm剩余的时间
1.1关键点
-
信号行为:
SIGALRM
默认终止进程,但可通过信号处理函数自定义行为。- 使用
signal
或sigaction
注册处理函数。推荐sigaction
以确保可移植性。
-
覆盖机制:
- 多次调用
alarm
会覆盖之前的定时器,返回前一个定时器的剩余时间。 - 调用
alarm(0)
取消定时器,返回剩余时间。
- 多次调用
-
精度与限制:
- 精度为秒级。更高精度需用
setitimer
或timer_create
。 - 与
sleep
等函数可能冲突(因内部使用相同信号),建议改用nanosleep
避免干扰。
- 精度为秒级。更高精度需用
-
多线程与进程:
- 定时器是进程级别的,多线程中需注意线程安全。
fork
后子进程不继承定时器;exec
会取消定时器。
应用场景
- 超时控制:如阻塞I/O操作设置超时,防止无限等待。
- 任务调度:定时执行特定任务(需结合信号处理)。
1.2单个alarm函数定时
程序:
#include <stdio.h>
#include <unistd.h>int main(int argc, char *argv[])
{unsigned int i;unsigned int sec;//当执行到alarm之后,代码会接着往下执行,当设定的时间到后,//会产生SIGALRM终止信号sec = alarm(5);printf("alarm返回值 = %d\n", sec);while(1){i++;printf("程序运行 第 %d 次\n",i);sleep(1);}return 0;
}
运行结果:alarm设置5秒的闹钟,程序运行5秒后,产生SIGALRM终止信号执行结束。
1.3两个alarm函数定时
程序:
#include <stdio.h>
#include <unistd.h>int main(int argc, char *argv[])
{unsigned int i;unsigned int sec;//当执行到alarm之后,代码会接着往下执行,当设定的时间到后,//会产生SIGALRM终止信号//如果alarm之前没有设置其他闹钟,则返回0,如果之前设置了,则返回之前剩余的秒数//如果一个程序中出现多个alarm闹钟,第一个如果没有到达指定的时间就遇到第二个//则第一个的闹钟时间清除,按照第二个alarm闹钟的时间继续向下运行sec = alarm(5);printf("alarm返回值 = %d\n", sec);sleep(2);//阻塞2秒sec = alarm(8);//返回上一个闹钟剩余时间printf("当前alarm 前面有alarm函数 返回值 = %d\n", sec);while(1){i++;printf("程序运行 第 %d 次\n",i);sleep(1);}return 0;
}
运行结果:
如果一个程序中出现多个alarm闹钟,第一个如果没有到达指定的时间就遇到第二个则第一个的闹钟时间清除,按照第二个alarm闹钟的时间继续向下运行。
程序中第一个闹钟先设置5秒,睡眠阻塞2秒,闹钟时间还剩余3秒,接着又遇见第二个闹钟设置8秒,第一个闹钟时间清零,闹钟时间按第二个闹钟运行。
2.raise函数
函数原型:
#include <signal.h>
int raise(int signum);功能:
给调用进程本身发送一个信号。参数:
signum:要发送的信号编号(如 SIGINT、SIGTERM 等)返回值:
成功返回 0,失败返回非0。
2.1核心行为
-
向自身进程发送信号
raise(sig)
等价于kill(getpid(), sig)
,但raise
是标准 C 库函数,可移植性更强。 -
触发信号处理逻辑
若已通过signal()
或sigaction()
注册了信号处理函数,调用raise
会执行对应的处理逻辑。 -
默认行为
若未捕获信号,执行信号的默认动作(如SIGTERM
会终止进程)。
2.2 raise与 kill 的区别
raise(sig) 等价 kill(getpid(), sig)
- raise 是进程内操作的简化版本,无需指定进程ID。
- raise 是标准 C 库函数,可移植性更强。
特性 | raise | kill |
---|---|---|
目标进程 | 仅当前进程 (getpid() ) | 可指定任意进程或进程组 |
信号来源 | 进程内部主动触发 | 通常由外部进程发送 |
可移植性 | 标准 C 库函数,跨平台兼容 | POSIX 系统调用 |
2.3程序:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>int main(int argc, char const *argv[])
{int num = 0;while(1){ sleep(1);num++;printf("程序运行 第 %d 次\n",num);//当循环执行5秒后,进程退出if(num == 5){//使用raise给当前进程本身发送信号raise(SIGTERM); //默认终止信号// raise(SIGALRM); //闹钟终止// raise(SIGINT); //终止,终端按下 Ctrl+C//kill(getpid(), SIGALRM);}}return 0;
}
运行结果:
3.abort函数
函数原型:
#include <stdlib.h>
void abort(void);功能:
向进程发送一个 SIGABRT 信号,默认情况下进程会退出。
默认行为是终止进程并生成核心转储文件(core dump)注意:即使 SIGABRT 信号被加入阻塞集,一旦进程调用了 abort 函数,
进程也还是会被终止,且在终止前会刷新缓冲区,关文件描述符。
程序:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>int main(int argc, char const *argv[])
{int num = 0;while(1){sleep(1);num++;printf("程序运行 第 %d 次\n",num);//当循环执行5秒后,进程退出if(num == 5){abort();//终止运行}}return 0;
}
运行结果:
4.pause 函数
函数原型:
#include <unistd.h>
int pause(void);功能:
将调用进程挂起直至捕捉到信号为止。这个函数通常用于判断信号是否已到。返回值:
直到捕获到信号,pause 函数才返回-1,且 errno 被设置成 EINTR。
4.1 pause简单挂起
(1)pause简单挂起返回值测试
程序:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>void alarm_handler(int sig)
{printf("定时器触发 SIGALRM 信号(%d)\n", sig);
}int main()
{signal(SIGALRM, alarm_handler);alarm(3); // 设置 3 秒定时int ret = pause(); // 等待定时器信号if (ret == -1) {if (errno == EINTR) {printf("pause 被 SIGALRM 中断\n");} else{perror("pause 错误");}}return 0;
}
运行结果:
(2)pause简单挂起,阻值while(1)运行
程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>int main(int argc, char *argv[])
{int num = 0;alarm(3);//设置3秒定时闹钟,3秒后,产生SIGALRM终止信号执行结束while(1){ sleep(1);num++;printf("程序运行 第 %d 次\n",num);pause(); // 进程挂起,等待信号}return 0;
}
运行结果:程序正常运行while(1)应每过一秒打印一次,加入pause进程挂起,等待信号,直到闹钟定时3秒后,发送终止信号,程序运行结束。
4.2父进程挂起,子进程发信号
程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>int main(int argc, char *argv[])
{pid_t pid;int num = 0;pid = fork();if(pid < 0){perror("fail to fork");//创建失败exit(1);//退出}else if(pid > 0) //父进程的代码区{printf("父进程运行... \n");//使用pause阻塞等待捕捉信号pause();// 进程挂起,等待信号}else //子进程的代码区 {printf("子进程运行... \n");while(1){sleep(1);//阻塞1秒num++;printf("子进程运行 第 %d 次 \n", num);if(num == 3){printf("给父进程发送终止信号 \n");//给父进程发送终止信号 kill(getppid(), SIGTERM);exit(1);//退出}}}return 0;
}
运行结果: