Linux signal与定时器

本文深入探讨了信号处理函数(signal)、终止进程信号(kill)、暂停进程(pause)、报警定时(alarm)以及定时器(setitimer)的用法与原理。详细解释了信号的类型、信号处理函数的作用及执行流程,以及如何通过kill和pause函数控制进程行为,通过alarm和setitimer实现精确定时。同时,介绍了不同类型的定时器及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. signal

sighandler_t signal(int signum, sighandler_t handler);

signum:是一个信号。除了SIGKILL和SIGSTOP外的任何一种信号
handler:

  1. 无返回值的函数地址
  2. SIG_IGN:忽略参数signum所指的信号
  3. SIG_DFL:恢复系统对信号的默认处理

注:当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断

查看64信号:
kill -l

2. kill

int kill(pid_t pid, int sig);
  1. 如果参数pid是正数,那么该调用将信号sig发送到进程号为pid的进程
  2. 如果pid等于0,那么信号sig将发送给当前进程所属进程组里的所有进程
  3. 如果参数pid等于-1,信号sig将发送给除了进程1和自身以外的所有进程
  4. 如果参数pid小于-1,信号sig将发送给属于进程组-pid的所有进程
  5. 如果参数sig为0,将不发送信号

3. pause

int pause(void);

当前的进程暂停(进入睡眠状态),直到被信号(signal)所中断

4. alarm

unsigned int alarm(unsigned int seconds);

说明:后一次设定将取消前一次的设定
注:一个进程只能有一个闹钟时间,如果在调用alarm之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替
返回值:返回上一个闹钟时间的剩余时间,否则返回0
信号:SIGALRM

5. setitimer
要求不太精确的话,使用alarm()和signal()就行了,但是如果想要实现精度较高的定时功能的话,就要使用setitimer函数

int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
struct itimerval
{
	struct timeval it_interval; //下一次的取值
	struct timeval it_value;    //本次的设定值
};

struct timeval
{
	long tv_sec;    //秒
	long tv_usec;   //微秒,1秒 = 1000000 微秒
};

which:

  1. ITIMER_REAL: 以系统真实的时间来计算,它送出SIGALRM信号
  2. ITIMER_VIRTUAL: -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号
  3. ITIMER_PROF: 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号

it_interval:指定间隔时间
it_value:指定初始定时时间

  1. 如果只指定it_value,就是实现一次定时
  2. 如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时
  3. 两者都清零,则会清除定时器

tv_sec:提供秒级精度
tv_usec:提供微秒级精度,以值大的为先
old_value:用来保存先前的值,常设为NULL

### Linux 信号处理机制 在 Linux 系统中,信号是一种异步通信方式,允许操作系统向进程发送通知消息。通过 `sigaction` 函数可以设置信号处理器的行为[^1]。 对于信号的捕获和响应,通常会定义一个自定义函数作为信号处理器,并将其关联到特定类型的信号上: ```c struct sigaction sa; sa.sa_handler = handler_function; // 自定义的信号处理函数 sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGALRM, &sa, NULL) == -1) { perror("Error setting signal action"); } ``` 这段代码展示了如何配置 SIGALRM 信号的动作,其中 `handler_function` 是用户编写的回调函数,在接收到定时器到期产生的 SIGALRM 后会被调用执行。 ### 定时器实现方法 #### 使用 `alarm()` 实现一次性定时器 `alarm()` 提供了一种简单的创建一次性的计时器的方式,它会在指定秒数后给当前进程发送一个 SIGALRM 信号[^2]: ```c unsigned int seconds = 5; alarm(seconds); // 设置五秒钟后的闹钟 pause(); // 阻塞等待直到SIGALRM到来 ``` 此段代码设置了五个单位时间长度的一次性定时器;当到达设定的时间点时,系统自动发出 SIGALRM 给该进程。 #### 利用 `setitimer()` 创建更精确的间隔定时器 如果需要更加精细控制以及重复触发的能力,则应该考虑采用 `setitimer()` 来代替 `alarm()`。它可以用来建立具有固定频率的周期性事件源。 ```c struct itimerval timer; timer.it_value.tv_sec = 0; timer.it_value.tv_usec = 500 * 1000; /* Initial delay */ timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 500 * 1000; /* Interval between signals */ // Set the ITIMER_REAL value to start a real-time interval timer. if (setitimer(ITIMER_REAL, &timer, NULL)) { perror("Failed to set timer"); } while(1){ pause(); printf("Timer expired\n"); } ``` 上述实例说明了怎样利用 `setitimer()` 建立每半秒发生一次的实时定时器,每次超时时都会激活 SIGALRM 并打印一条信息。 #### 用户态下的高级定时器管理方案 除了基本 API 外,还有其他更为复杂的解决方案适用于高并发场景下大量活跃定时任务的情况。例如,基于红黑树的数据结构被广泛应用于高效地维护多个待定事件列表之中[^4]。 这些数据结构能够有效地支持动态增删节点操作的同时保持较好的性能特性,从而使得应用程序能够在面对成千上万个独立运行的小型延时期间依然维持良好的反应速度和服务质量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值