linux 信号

8 篇文章 0 订阅
6 篇文章 0 订阅

前言

        信号是在软件层面上对中断的模拟,也叫软中断信号,用于通知应用程序发生了异步事件。信号不进行数据传递,仅向进程传递异步事件。

        当硬件检测到异常时,将异常信息发给内核,内核再把异常信号通知到进程中;shell终端也可以生成信号,并通知给前台进程;程序中也可以通过系统调用,生成的信号可以发给自己,也可以发给其它进程。

1. 信号分类

在linux系统shell终端中输入命令“kill -l”查看内核中维护的信号,由信号编号(数字部分)和信号名组成。向进程发送信号的命令格式为“kill -编号 pid”,我们常用的“kill -9 pid”命令就是使用编号为9的信号来终止进程。

可以使用命令“man 7 signal”查看详细内容。

来源于迅为文档

1.1  不可靠信号

早期的unix系统中,信号的处理机制存在很多问题,例如信号捕获后,下次该信号触发时又恢复到系统默认处理了,需要在自定义的信号处理函数中重新配置处理函数;还有就是在信号处理过程中再次触发了新信号,此时这个信号可能就会丢失掉。

编号小于SIGRTMIN(编号34)的信号被叫做不可靠信号或非实时信号,linux系统继承了unix的这种不可靠信号,也对它做了改进,信号捕获处理函数配置了一次就不会跳回到系统默认处理了,但还是存在丢失的情况。

1.2 可靠信号

由于不可靠信号被应用在了很多方面,为了兼容性,对之前的不可靠信号不改动,新增加一些优化后的信号,SIGRTMIN(编号34)到SIGRTMAX(编号64)的信号被称为可靠信号或实时信号。可靠信号修复了unix信号机制的那两个问题,信号不丢失。

2. 信号处理

当进程接收到信号后,通常有三种处理方式:①系统默认处理方式,②忽略信号,③捕获信号自定义处理。系统调用提供了信号处理API。

2.1 signal()函数

signal()和sigaction()都可以用来设置信号处理函数,但sigaction函数更复杂一点。

头文件:

#include <signal.h>

typedef void (*sighandler_t)(int);

函数原型:

sighandler_t signal(int signum, sighandler_t handler);

参数:

signum:指定信号;例如SIGINT;

handler:

        SIG_IGN:忽略该信号;

        SIG_DFL:系统默认处理方式;

        void (*sighandler_t)(int):捕获信号自定义处理函数;

返回值:

成功:返回最后一次注册信号调用signal()时的handler 值;

失败:返回SIG_ERR。//#define SIG_ERR ((sig_t) -1)

#include <stdio.h>
#include <signal.h>

void sig_handler(int sig)
{
    printf("signal handler...\n");
}

int main()
{
    signal(SIGINT,sig_handler);
    while(1);
    return 0;
}

3. 进程中发送信号

信号也可以在进程中通过系统调用API来发送,接收方可以是本身进程或者其它进程。

3.1 kill函数

向指定的进程中发送指定的信号。

头文件:

#include <sys/types.h>

#include <signal.h>

函数原型:

int kill(pid_t pid, int sig)

参数:

pid

        大于0,向指定pid 的进程发送信号;
        等于0,向同一个进程组的进程发送信号;
        等于-1,除发送进程自身外,向所有进程ID 大于1 的进程发送信号;
        小于-1,向进程组ID 等于该pid 绝对值的进程组内所有进程发送信号;

sig:指定要发送的信号;设为 0 表示空信号

返回值:

成功:返回 0 ;

失败:返回 -1

测试例程:

打开两个shell终端,在sig.c中设置信号捕获处理函数,kill.c中向指定进程中传入信号。

sig.c代码:

#include <stdio.h>
#include <signal.h>

void sig_handler(int sig)
{
    printf("signal handler...\n");
}

int main()
{
    signal(SIGINT,sig_handler);
    while(1);
    return 0;
}




kill.c代码:

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    if(argc < 2){
        printf("please input argv[1].\n");
        exit(0);
    }

    kill(atoi(argv[1]),SIGINT);
    return 0;
}

3.2 raise函数

相比于kill函数,raise函数只能对自身进程发送信号。

头文件:

#include <signal.h>

函数原型:

int raise(int sig)

参数:

sig:指定要发送的信号;

返回值:

成功:返回 0;

失败:返回非零值

4. 信号其它API

4.1 alarm函数

alarm函数用于设置一个定时器,时间到达时,内核会向调用进程中发送SIGALRM信号。

头文件:

#include <unistd.h>

函数原型:

unsigned int alarm(unsigned int seconds)

参数:

seconds:以秒为单位设置时间;0 表示取消之前设置的定时器;

返回值:

成功:调用alarm()前已经设置过定时器了,且还没有超时,则返回剩余未超时的时间值,同时时间也被更新;如果之前未设置,则返回 0。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

int main()
{
    int ret = -1;
    int time = 10;
    alarm(10);
    sleep(5);
    ret = alarm(10);
    printf("ret = %d\n",ret);
    while(1)
    {
        printf("sleep:%d\n",time--);
        sleep(1);
    }
    return 0;
}

 4.2 pause函数

系统调用函数pause()使进程停止,进入休眠状态,当捕获到信号,且从信号处理函数返回时,pause才退出返回,没有捕获信号之前pause一直返回 -1 。

头文件:

#include <unistd.h>

函数原型:

int pause(void)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值