Linux c 信号操作(alram,setitimer,signal,sigaction函数使用)

本文介绍了Linux中信号的基础概念,包括其简单性、不可携带大量信息的特性以及信号如何中断程序执行。讨论了信号的递达和未决状态,以及信号屏蔽字和未决信号集的作用。同时,讲解了信号的三种处理方式:默认动作、忽略和捕捉。接着,通过实例展示了如何使用alarm和setitimer函数进行计时,并在接收到SIGALRM信号时执行自定义函数。最后,通过sigaction函数捕获并处理SIGINT信号,展示了信号捕捉的特性和应用。

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


Linux c 通过信号回收N个子进程

1、信号基础概念

信号共性:
    简单、不能携带大量信息,满足条件才发送

信号特质:
    信号是软件层面上的”中断“,一旦信号产生,无论程序执行到什么位置,必须立即停止运行,处理结束,在继续执行后续指令

# 所有信号的产生和发送都是内核来处理的

递达:成功由内核产生,并且成功发送到指定进程
未决:处于发送和递达之间的状态(主要由于阻塞屏蔽导致该转态)

信号屏蔽字:
	将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,在收到该信号,该信号的处理将推后(解除屏蔽后在处理)

未决信号集(用来记录信号处理状态):
	1、信号产生,未决信号集中描述该信号的位立即翻转为1,表信号处于未决状态,当信号被处理对应位翻转回为0,这一时刻往往非常短暂
	2、信号产生后由于某些原因(主要是阻塞)不能抵达,这类信号的集合称之为未决信号集,在屏蔽解除前,信号一直处于未决转态

# 信号处理方式:
1、执行默认动作
2、忽略(丢弃)
3、捕捉(调用户处理函数)

2、计时函数使用

2.1、alarm函数(定时发送SIGALRM给当前进程,默认动作为终止进程)

unsigned int alarm(unsigned int seconds);
参数:
    seconds 定时秒数
返回值:
    上次定时闹钟剩余时间
    无错误现象

2.2、setitimer函数(定时发送SIGALRM给当前进程,默认动作为终止进程)

int setitimer(int which,const struct itimerval* new_value,struct itimerval* old_value);
参数:
    which 
        ITIMER_REAL (14 SIGLARM) 自然时间
        ITIMER_VIRTUAL(26 SIGVTALRM) 虚拟空间时间(只计算进程占用cpu的时间)
        ITIMER_PROF (27 SIGPROF) 运行时计时(用户+内核,)
    new_value 定时秒数
        it_interval:用来设定两次定时任务之间间隔的时间
        it_value:定时的时长
    old_value 上次定时闹钟剩余秒数
返回值:
    成功 0
    失败 -1

两个都是计时函数,但是第二个更精细,可以设置每次调用的间隔时间,和微秒数

2.3、使用两个还是分别实现1秒中,能打印多少数到屏幕
alarm函数

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

int main()
{
    int i=1;
    alarm(1);
    while(i++)
    {
        printf("%d\n",i);
    }
    return 0;
}

setitimer函数

#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

void sys_perror(const char* str)
{
    perror(str);
    exit(1);
}

int main()
{	// 参数初始化
    struct itimerval it,oldit;
    it.it_value.tv_sec = 1;    // 设置秒说
    it.it_value.tv_usec = 0;

    it.it_interval.tv_sec = 0;  // 设置间隔为0秒
    it.it_interval.tv_usec = 0;
	
	// 错误检查
    if(setitimer(ITIMER_REAL,&it,&oldit) == -1) 
        sys_perror("setitimer error");
        
    int i=1;
    while (i++)
    {
        printf("%d\n",i);
    }
    return 0;
}

两个函数实现效果一样,程序运行1秒钟之后就会,发送SIGALRM给当前进程,默认动作为终止进程

上面的概念说到,信号的处理动作有三种:执行默认动作、忽略、捕捉
现在我们将SIGALRM进行捕捉,然后执行我们自定义的函数,让他每次发送SIGALRM信号打印“hello world”

2.4、通过signal函数捕捉SIGALRM信号
signal函数

typedef void (*sighandler_t)(int);
sighandler_t signal(int signo,sighandler_t handler);
参数:
    signo 信号编号
    handler 回调函数(返回值void参数为int的函数类型)
   
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

void sys_perror(const char* str)
{
    perror(str);
    exit(1);
}

void fun2(int signo)
{
    printf("hello world\n");
}

int main()
{
    struct itimerval it,oldit;
    signal(SIGALRM,fun2);   // 注册SIGALRM信号的捕捉处理函数
    it.it_value.tv_sec = 2;    // 设置秒说
    it.it_value.tv_usec = 0;

    it.it_interval.tv_sec = 5;  // 设置间隔为5秒
    it.it_interval.tv_usec = 0;

    if(setitimer(ITIMER_REAL,&it,&oldit) == -1) 
        sys_perror("setitimer error");


    while (1); // 模拟下面行为
    return 0;
}

2.5、通过sigaction捕捉ctrl+c(用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。)

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
参数:
	signum 信号编号
	act 默认需要初始化结构体
	oldact 旧的结构体(一步不使用可以传NULL)

返回值:
	成功 0
	失败 -1
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

void sys_perror(const char* str)
{
    perror(str);
    exit(1);
}

void cat_sig(int signo)
{
    printf("hello world %d\n",signo);
}

int main()
{
    struct sigaction act,oldact;
    act.sa_handler = cat_sig; // 设置信号捕捉函数
    sigemptyset(&(act.sa_mask));    // 设置信号捕捉期间mask
    act.sa_flags = 0;   // 设置默认属性
    
    int ret = sigaction(SIGINT,&act,&oldact);
    if(ret == -1)
        sys_perror("sigaction error");
    // signal(SIGINT,cat_sig);
    while(1);
    return 0;
}
信号捕捉特性:
sa_mask 只工作信号捕捉函数执行期间,
    1、捕捉函数执行期间,信号屏蔽字,由mask->sa_mask,捕捉函数执行结束,恢复mask
    2、捕捉函数执行期间,本信号自动被屏蔽(sa_flgs=03、捕捉函数执行期间,被屏蔽信号多次发送,解除屏蔽后只处理一次
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

讳疾忌医丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值