【Linux】进程信号,相关函数的简单实用




一、讨论范围

在这里插入图片描述

  • 编号34以上的信号叫做实时信号,不在讨论范围内
  • 上图中信号的产生方式和默认处理动作可以通过
    man 7 signal指令来查看

二、信号的结构

1.信号的本质

task_struct内部存在一个位图结构,用int表示:uint32_t signals;
0000 0000 0000 0000 0000 0000 0000 0000

所谓的发送信号其实就是修改特定进程信号位图的特定比特位

  • 比特位的位置就是信号的编号
  • 比特位的内容表示1是否收到信号

2.预备知识

2.1 如何发送信号

kill options PID
其中,PID是进程的ID,可以是单个进程的ID,也可以是多个进程的ID,用空格分隔

eg:
给ID为1234的进程发送2号信号
kill -2 1234

该处使用的url网络请求的数据。

2.2 如何查看后台程序

ps aux | grep 名称关键词

eg:
查找名称与“chrome”相关的后台程序
ps aux | grep chrome


三、改变信号默认触发方式的两个函数

举个例子,在我们不小心写出死循环,或者故意写出死循环以便于使程序持续运行的时候,通常会在命令行输入“Ctrl+C”来停止命令行的无限刷屏,而我们输入的“Ctrl+C”,实际上就是给我们提到的死循环程序发送了2号信号;
下面是两个函数,它们的功能可以让一个程序在接收到2号信号时继续运行,而不是就此退出

1.signal

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

功能为“在收到signum号信号的时候执行handler函数”

eg:signal(2,handler) signal(SIGQUIT,handler)
两种写法都可以,signum可以是除了SIGKILL和SIGSTOP以外的任何有效信号

示例代码:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigcb()
{
    printf("SIGINT\n");
}
int main()
{
    signal(SIGINT,(sighandler_t)sigcb);
    while(1)
    {

        printf("m alive\n");
        sleep(2);
    }
    return 0;
}

运行结果:
在这里插入图片描述
按下“Ctrl+C”也会有类似的结果
在这里插入图片描述

自己想试一下的话后面可以用“Ctrl+Z”结束这个程序,向它发送9号信号也可以,因为SIGKILL和SIGSTOP这个两个信号不能被系统忽略,也不能被改变默认处理动作

man一下之后可以发现使用文档表示这个函数已经过时了,而且不同系统版本下signal函数的功能也可能不一样

2.sigaction

#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);

也是用来改变进程对于已接收信号做出的行动;
signum可以是任何除了SIGKILL和SIGSTOP以外的有效信号;
如果act不是NULL,则从act安装信号signum的新动作。如果oldact不是NULL,先前的操作保存在oldact中。

所以为了使用这个函数,struct sigaction的结构也必须了解

The sigaction structure is defined as something like:
           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };
  • sa_handler就是接收到signum信号以后被调用的新方法,使用的时候先声明一个这样的结构体,然后再把函数指针指向你想要的函数就好了
  • 不要同时给sa_handler和sa_sigaction同时赋值
  • sa_restorer这个成员已经过时了,别用
  • 如果sa_flags被指定为SA_SIGINFO,收到signum对应的信号以后就执行sa_sigaction指向的函数(sa_handler这时候就没用了),这个函数把int作为其第一个参数,一个指向siginfo_t的指针作为其第二个参数,并将指向ucontext_t(强制转换为void *)的指针作为其第三个参数。(通常,handler函数不使用第三个参数)
  • sa.sa_flags = 0; 表示将 sa_flags 字段设置为零,表示使用默认的标志位,即默认的信号处理行为。

示例代码:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sigcb(int m)//为了不报错所以弄成了和结构体中指针相匹配的类型
{
    printf("SIGINT\n");
}
int main()
{
    struct sigaction m;
    m.sa_handler=sigcb;
    sigaction(SIGINT,&m,NULL);
    while(1)
    {
        printf("m alive\n");
        sleep(1);
    }
    return 0;
}

运行结果:
在这里插入图片描述

四、信号集操作函数和相关指令

这里的“信号集操作函数”指的就是用来操作signal mask的函数;
在 Unix 系统中,每个进程都有一个信号掩码signamask,用于管理它希望阻塞或允许传递的信号。sigprocmask 函数允许程序员操作这个信号掩码,以便选择性地阻塞或解除阻塞特定的信号。

#include <signal.h>

用起来也是事先声明好一个sigset_t类型的信号集``

0.sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

oldset用来存储set的前一个值,也就是说如果oldset为非null,则信号掩码的前一个值存储在oldset中。
如果set为NULL,则信号掩码不变(忽略how),信号掩码的当前值仍然在oldset中返回(如果oldset不是的话)
参数how的参数:
在这里插入图片描述

1.sigemptyset

int sigemptyset(sigset_t *set);

函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。

2.sigaddset

int sigaddset (sigset_t *set, int signo);

添加一个signo信号到set这个信号集里面,使signo这个信号变成可以接收到的有效信号

3.sigdelset

int sigdelset(sigset_t *set, int signo);

把set信号集里面的signo信号删了

4.sigfillset

int sigfillset(sigset_t *set);

函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系
统支持的所有信号。

示例代码:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main()
{
    sigset_t tmp;
    sigemptyset(&tmp);
    sigaddset(&tmp,2);
    sigaddset(&tmp,40);
    sigprocmask(SIG_BLOCK,&tmp,NULL);
    while(1)
    {
        printf("m alive\n");
        sleep(1);
    }
    return 0;
}

把2号信号和40号信号都屏蔽了,然后再向test3发送这两个信号,发现什么事也没有发生:
在这里插入图片描述


总结

之前那篇讲共享内存的博客相对来说数据比较好,原因可能是我是读了man的使用手册以后按我理解的逻辑顺序讲的,而且我个人认为使用文档里对函数的说明比博客和百度要全面一些
有一些函数因为使用文档太长了所以我只挑了比较重要的部分来讲,如有遗漏欢迎指出
感谢支持

  • 22
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Alexanderite

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

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

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

打赏作者

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

抵扣说明:

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

余额充值