1、 定时信号SIGALRM的用途
在编程的过程中,很多时候我们需要为程序设置一个闹钟,然后到了闹钟设定的时刻然后再去采取相关的操作。比如进行socket编程时,如果客户端长时间没有与服务器进行交互,需要服务器在一定时间之后主动关闭socket连接。在这种场景下,就可以在服务器收到客户端的socket的连接时,设置一个定时信号,然后在定时信号到来时,关闭掉socket连接即可。
2、定时信号SIGALRM的触发
通过alarm函数触发定时信号,在linux系统中,alarm函数需要的头文件为:
#include <unistd.h>
函数原型如下:
unsigned int alarm(unsigned int seconds)
/*
参数:
seconds:表示在当前时刻seconds秒之后产生一个SIGALRM信号,若seconds=0,表示取消闹钟
返回值:
0或者一个大于0的值。若值大于0,表示上一个定时器还剩余多少秒。比如:
int ret1 = alarm(10); // 第0秒时刻,设定一个定时闹钟,准备10秒后触发SIGALRM信号, 此时返回值为0
sleep(5);
int ret2 = alarm(20); // 重新设定闹钟,定时信号将会在第25秒触发,此时ret2=5,表示上个闹钟还剩余5秒
*/
几点说明:
- 闹钟信号只会触发一次,若想循环触发,可以在闹钟到时后重新通过alarm函数触发
- 可以重新设置闹钟信号,即在上一个闹钟到时之前,通过alarm函数重新设定响铃时刻或取消闹钟
3、定时信号的响应与捕捉
3.1 系统默认对SIGALRM信号的响应
如果不对SIGALRM信号进行捕捉或采取措施,默认情况下,闹钟响铃时刻会退出程序。观察下面的程序:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int main() {
int t = alarm( 5 ); // 设定闹钟5秒之后响铃
printf("set alarmer: %d \n", t);
sleep(2);
int ret = alarm(4); // 重新设定闹钟4秒之后响铃,上一个闹钟还剩3秒
printf("reset alarmer: %d \n", ret);
int i;
for ( i = 0; i < 15; i++ )
{
printf( " sleep % d ... \n ", i );
sleep( 1 );
}
return 0;
}
打印如下:
从上面可以看到,重新设定闹钟在4秒之后响铃,4秒之后,屏幕打印:Alarm clock,
然后程序就退出了。
3.2 设置SIGALRM信号的响应函数
既然设定闹钟信号,肯定是希望在闹钟响铃的时刻采取一定的操作,这个操作自然是通过执行某个函数来实现。因此,我们需要为SIGALRM信号设定一定响应函数(回调函数),然后响铃的时候就会执行该函数。
信号回调函数的设置是通过sinal函数来进行的。需要对头文件为signal.h,signal.h是C标准函数库中的信号处理部分,定义了程序执行时如何处理不同的信号。函数原型如下:
// 位于头文件 signal.h
// Type of a signal handler
typedef void (*__sighandler_t)(int);
__sighandler_t signal(int __sig, __sighandler_t __handler);
/*
入参:
__sig:表示要捕捉的信号,如果要捕捉SIGALRM信号,这里填SIGALRM即可
__handler:回调函数(其实还可以设置其它值,具体见参考文章1)
返回值:
返回指向回调函数的函数指针,若有错误则返回SIG_ERR (-1)
*/
示例如下:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
/*闹钟信号处理函数*/
void sig_handler() {
printf( "hello world! \n " );
}
int main() {
signal( SIGALRM, sig_handler );
int t = alarm( 5 );
printf("set alarmer: %d \n", t);
sleep(2);
int ret = alarm(4);
printf("reset alarmer: %d \n", ret);
for (int i; i = 0; i < 15; i++ )
{
printf( " sleep % d ... \n ", i );
sleep( 1 );
}
return 0;
}
打印如下:
可以看到,定时信号到时,调用了响应函数sig_handler,并打印出了hello world,然后程序继续执行。
【参考文章】
1、https://blog.csdn.net/yyyljw/article/details/80741264