0
点赞
收藏
分享

微信扫一扫

linux-信号

菜头粿子园 2022-02-07 阅读 108
linux

什么是信号?

        信号是事件发生时对进程的通知机制,也可以把它称为软件中断。信号与硬件中断的相似之处在于能够打断程序当前执行的正常流程,其实是在软件层次上对中断机制的一种模拟。

信号的本质?

        信号本质上是 int 类型的数字编号,这就好比硬件中断所对应的中断号。内核针对每个信号,都给其定义了一个唯一的整数编号,从数字 1 开始顺序展开。

 信号的作用?

        用于进程间通讯,达到通讯、同步等目的。

产生信号的情况有哪些?

        1、 硬件发生异常,即硬件检测到错误条件并通知内核,随即再由内核发送相应的信号给相关进程。

        2、用于在终端下输入了能够产生信号的特殊字符。譬如在终端上按下 CTRL + C 组合按键可以产生中断信号(SIGINT),通过这个方法可以终止在前台运行的进程;按下 CTRL + Z 组合按键可以产生暂停信号(SIGCONT),通过这个方法可以暂停当前前台运行的进程。

        3、进程调用 kill()系统调用可将任意信号发送给另一个进程或进程组。当然对此是有所限制的,接收信号的进程和发送信号的进程的所有者必须相同,亦或者发送信号的进程的所有者是 root 超级用户。

        4、用户可以通过 kill 命令将信号发送给其它进程。kill 命令想必大家都会使用,通常我们会通过 kill命令来“杀死”(终止)一个进程,譬如在终端下执行"kill -9 xxx"来杀死 PID 为 xxx 的进程。kill命令其内部的实现原理便是通过 kill()系统调用来完成的。

        5、发生了软件事件,即当检测到某种软件条件已经发生。

信号到达后如何处理?

        1、忽略信号。也就是说,当信号到达进程后,该进程并不会去理会它、直接忽略,就好像是没有出该信号,信号对该进程不会产生任何影响。

        2、捕获信号。当信号到达进程后,执行预先绑定好的信号处理函数。Linux 系统提供了 signal()系统调用可用于注册信号的处理函数。

        3、执行系统默认操作。进程不对该信号事件作出处理,而是交由系统进行处理,每一种信号都会有其对应的系统默认的处理方式。

信号的分类?

        Linux 系统下可对信号从两个不同的角度进行分类,从可靠性方面将信号分为可靠信号与不可靠信号;而从实时性方面将信号分为实时信号与非实时信号。

        可靠信号与不可靠信号:可靠信号支持排队,不会丢失不可靠信号不支持排队,可能会丢失

        实时信号与非实时信号:与可靠信号与不可靠信号是相互对应的,非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。

相关联的几个关键API函数:

        1、向进程发送信号(对其他进程):int kill(pid_t pid, int sig);

              对自己发送信号:int raise(int sig);

        2、绑定接受信号处理函数:sig_t signal(int signum, sig_t handler);

        3、定时闹钟:unsigned int alarm(unsigned int seconds);

              内核会按照设定的时间定时向进程发送SIGALRM信号。

        4、暂停/休眠进程:int pause(void);

              可以使得进程暂停运行、进入休眠状态,直到进程捕获到一个信号为止,只有执行了信
号处理函数并从其返回时,pause()才返回。

什么是信号集合?

         一个能表示多个信号(一组信号)的数据类型。一般用内核定义的sigset_t 结构体表示。

信号集合操作相关的API函数?

        1、sigemptyset()和 sigfillset()用于初始化信号集。sigemptyset()初始化信号集,使其不包含任何信号;而sigfillset()函数初始化信号集,使其包含所有信号(包括所有实时信号)。

        2、 sigaddset()和 sigdelset()函数向信号集中添加或移除一个信号。

        3、 sigismember()函数可以测试某一个信号是否在指定的信号集中。

什么是信号掩码?

        内核为每一个进程维护了一个信号掩码(其实就是一个信号集),即一组信号。当进程接收到一个属于信号掩码中定义的信号时,该信号将会被阻塞、无法传递给进程进行处理,那么内核会将其阻塞,直到该信号从信号掩码中移除,内核才会把该信号传递给进程从而得到处理。

        一句话就是信号掩码集合中的信号不能被传递给进程。

如何为一个进程设置信号掩码集合?

        

        how :参数 how 指定了调用函数时的一些行为。
        set :将参数 set 指向的信号集内的所有信号添加到信号掩码中或者从信号掩码中移除;如果参数 set 为NULL,则表示无需对当前信号掩码作出改动。
        oldset: :如果参数 oldset 不为 NULL,在向信号掩码中添加新的信号之前,获取到进程当前的信号掩码,存放在 oldset 所指定的信号集中;如果为 NULL 则表示不获取当前的信号掩码。
返回值:成功返回 0;失败将返回-1,并设置 errno。
        参数 how 可以设置为以下宏:
        ⚫ SIG_BLOCK:将参数 set 所指向的信号集内的所有信号添加到进程的信号掩码中。换言之,将信号掩码设置为当前值与 set 的并集。
        ⚫ SIG_UNBLOCK:将参数 set 指向的信号集内的所有信号从进程信号掩码中移除。
        ⚫ SIG_SETMASK:进程信号掩码直接设置为参数 set 指向的信号集。

sigsuspend()函数的解释?

        sigsuspend()函数会将参数 mask 所指向的信号集来替换进程的信号掩码,也就是将进程的信号掩码设置为参数 mask 所指向的信号集,然后挂起进程,直到捕获到信号被唤醒(如果捕获的信号是 mask 信号集中的成员,将不会唤醒、继续挂起)、并从信号处理函数返回,一旦从信号处理函数返回,sigsuspend()会将进程的信号掩码恢复成调用前的值。

        一句话就是调用这个函数后进程会被挂起,直到接收到非信号掩码集合中的信号才会唤醒进程继续往下执行。

如何查询等待信号集合?

        如果进程当前正在执行信号处理函数,在处理信号期间接收到了新的信号,如果该信号是信号掩码中的成员,那么内核会将其阻塞,将该信号添加到进程的等待信号集(等待被处理,处于等待状态的信号)中,为了确定进程中处于等待状态的是哪些信号,可以使用 sigpending()函数获取。

 

 如何向一个进程发送实时信号?

        前面我们提到实时信号和非实时信号,实时信号的话它是不对丢次数的,需要调用int sigqueue(pid_t pid, int sig, const union sigval value)函数向一个进程发送但数据信息的实时信号。

如何获取信号的描述信息?

        在 Linux 下,每个信号都有一串与之相对应的字符串描述信息,用于对该信号进行相应的描述。

         或者用 strsignal()函数。

 

举报

相关推荐

0 条评论