Linux系统编程-信号(黑马笔记)
当一个进程跟另外一个进程发送信号后,接收信号的进程有以下几种行为:
1.执行默认处理 2.忽略 3.捕捉后特定处理
1.kill函数
发送信号的函数
#include <sys/types.h>
#include <signal.h>int kill(pid_t pid, int sig);
参数说明
pid
:指定接收信号的进程 ID(进程标识符),有几种特殊情况:pid > 0
:向 PID 为pid
的单个进程发送信号。pid = 0
:向当前进程所在的进程组中所有进程发送信号。pid = -1
:向系统中所有有权限发送的进程发送信号(一般用于管理员操作)。pid < -1
:向 PID 为|pid|
的进程组中所有进程发送信号。
sig
:指定要发送的信号(如SIGKILL
、SIGTERM
、SIGALRM
等):- 常见信号:
SIGKILL
(强制终止进程,无法被捕获或忽略)、SIGTERM
(请求终止进程,可被捕获处理)、SIGSTOP
(暂停进程)等。 - 若
sig = 0
:不发送任何信号,仅用于检查目标进程是否存在(返回值可判断进程是否存活)。
- 常见信号:
返回值
- 成功:返回
0
。 - 失败:返回
-1
,并设置errno
表示错误原因(如目标进程不存在、无权限发送信号等)。 - 这里必须在父进程中找到对应的子进程id
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>void sys_err(const char *str)
{perror(str);exit(1);
}int main()
{pid_t pid;pid_t res;int i;for(i=0;i<5;i++){pid = fork();if(i==2){//这里必须在父进程中获取子进程的id才行res = pid;}if(pid==0) {break;} // 子进程跳出循环}if (pid > 0) {sleep(5); // 让子进程先运行一会// 向子进程发送SIGTERM信号if (kill(res, SIGTERM) == -1) {sys_err("kill error");}printf("parent process send SIGTERM to child process\n");} else if (pid == 0) {while (1) {printf("child process is running, my = %dth\n", i+1);sleep(1);}} else {sys_err("fork error");}return 0;
}
2.alarm函数
alarm
函数是 Unix/Linux 系统中用于设置一次性定时器的系统调用,作用是在指定时间(秒数)后,向当前进程发送 SIGALRM
信号(与之前提到的定时器信号相同)。
函数原型
#include <unistd.h>unsigned int alarm(unsigned int seconds);
参数与返回值
参数
seconds
:指定定时器的秒数。- 若
seconds = 0
:取消当前已设置的闹钟(如果存在)。 - 若
seconds > 0
:设置一个新的闹钟,seconds
秒后发送SIGALRM
信号。
- 若
返回值:
- 如果之前没有设置过未到期的闹钟,返回
0
。 - 如果之前已设置过闹钟且尚未到期,返回剩余的秒数(即距离上一个闹钟到期还剩多少秒),同时新的闹钟会覆盖旧的设置。
- 如果之前没有设置过未到期的闹钟,返回
核心功能
alarm
函数会让系统在 seconds
秒后,自动向当前进程发送 SIGALRM
信号。默认情况下,SIGALRM
信号的处理行为是终止进程,但可以通过 signal
函数注册自定义处理函数(如之前代码中的 myfunc
),从而实现 “定时执行某个操作” 的效果。
需要注意的是:alarm
是一次性定时器,信号触发后定时器自动失效,若需周期性触发,需在信号处理函数中再次调用 alarm
重置。
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
int main(void)
{int i;//自然时间alarm(1);for(i = 0; ; i++)printf("%d\n", i);return 0;
}
3.setitimer函数
等待的时间和定时器的时间内,是不是都在运行主程序,只是时间到了会触发中断,运行一次处理函数,然后继续执行主程序?
豆包答:是的,你的理解完全正确
函数原型
#include <sys/time.h>int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
参数说明
which
:指定定时器类型,有 3 种可选:ITIMER_REAL
:实时时钟(以系统真实时间计时),到期后发送SIGALRM
信号(与alarm
一致)。ITIMER_VIRTUAL
:虚拟时钟(仅计算进程在用户态运行的时间),到期后发送SIGVTALRM
信号。ITIMER_PROF
:统计时钟(计算进程在用户态 + 内核态的总运行时间),到期后发送SIGPROF
信号。(最常用的是ITIMER_REAL
,对应真实时间的定时)
new_value
:指向struct itimerval
结构体的指针,用于设置定时器的参数(首次触发时间和周期),结构体定义如下:c
运行
struct itimerval {struct timeval it_interval; // 周期性触发的时间间隔(0表示仅触发一次)struct timeval it_value; // 首次触发的延迟时间(0表示关闭定时器) };struct timeval {time_t tv_sec; // 秒数suseconds_t tv_usec; // 微秒数(0-999999) };
old_value
:指向struct itimerval
结构体的指针,用于存储上一次定时器的设置(若不需要可传NULL
)。
返回值
- 成功:返回
0
。 - 失败:返回
-1
,并设置errno
表示错误原因(如参数无效)。
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>
int count=0;
void myfunc(int signo)
{printf("count = %d\n",count);count=0;
}int main(void)
{struct itimerval it, oldit;signal(SIGALRM, myfunc); //itvalue:第一次定时器到期的时间间隔it.it_value.tv_sec = 1;it.it_value.tv_usec = 0;//itinterval:后续定时器到期的时间间隔 sec是秒,usec是微秒两个之和是最后的时间it.it_interval.tv_sec = 2;it.it_interval.tv_usec = 0;if (setitimer(ITIMER_REAL, &it, &oldit) == -1){perror("setitimer error");return -1;}while (1){count++;}return 0;
}