Linux系统编程之Linux 信号集编程:信号集的基本概念、用法和实现方式

简介: Linux系统编程之Linux 信号集编程:信号集的基本概念、用法和实现方式

信号集

表示多个信号的集合

信号在内核中的表示

信号递达(Delivery):实际执行信号处理的动作。

信号未决(Pending):信号从产生到递达之间的状态。

信号阻塞(Block)    :被阻塞的信号产生时将保持在未决状态,直到 进程解除对此信号的阻塞,才 执行递达的动作。

注意:

信号阻塞和信号忽略是不同的。只要信号被阻塞就不会递达,除非解除阻塞,而忽略是在递达之后 可选的一种处理动作。

一个信号处于Pending状态,屏蔽之后,它永远不会被Delivery 。

一个信号是否立即Delivery ,与Block没有绝对关

3张表的存储:

pending表:  用4个字节的位图表示,位图的位置表示信号编号,内容表示是否pending。

block表:      用4个字节的位图表示,位图的位置表示信号编号,内容表示是否block。

handler表:     是一个句柄函数指针,数组即可表示,下标表示信号编号,内容表示信号处理的动作,为NULL表示没有处理该信号。

分析上图中的信号:
1〉SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。
2〉SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。
3〉 SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。

 

信号集接口函数

sigemptyset      置空一个信号集
sigfillset           填充满一个信号集
sigaddset         将一个信号加入信号集
sigdelset        将一个信号从信号集删除
sigismember     检查一个信号集中是否有这个信号

  • 信号集增减操作
#include <signal.h>
 
    int sigemptyset(sigset_t *set);//将set集合置空
 
  int sigaddset(sigset_t *set,int signo);//将signo信号加入到set集合
  int sigdelset(sigset_t *set,int signo);//从set集合中移除signo信号
 
 
   int sigfillset(sigset_t *set); //将所有信号加入set集合
 

返回值:

        若成功,返回0

        若出错,返回-1

  • 测试信号是否已加入信号集
int sigismember(const sigset_t *set, int signum); //测试参数signum 代表的信号是否已加入至参数set信号集里

返回值:

        若成功,返回0

        若出错,返回-1

  • 设定对信号集处理方式
int sigdelset(sigset_t *set,int signo);
//设定对信号屏蔽集内的信号的处理方式(阻塞或不阻塞)。

参数:

how:用于指定信号修改的方式,可能选择有三种:

SIG_BLOCK //加入信号到进程屏蔽。

SIG_UNBLOCK //从进程屏蔽里将信号删除。

SIG_SETMASK //将set的值设定为新的进程屏蔽。

set:指向信号集的指针,在此专指新设的信号集,如果仅想读取现在的屏蔽值,可将其置为NULL。

oldset:也是指向信号集的指针,在此存放原来的信号集。

返回值:

        若成功,返回0

        若出错,返回-1,errno被设为EINVAL。

  • 等待信号
int sigsuspend(const sigset_t *sigmask);
 
//该函数通过将进程的屏蔽字替换为由参数sigmask给出的信号集,然后挂起进程的执行。注意操作的先后顺序,是先替换再挂起程序的执行。程序将在信号处理函数执行完毕后继续执行。
 
/*
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
*/

参数说明

  sigmask 希望屏蔽的信号

返回值

       若接收到信号终止了程序,sigsuspend()就不会返回。

        若出错(接收到的信号没有终止程序),返回-1,并将errno设置为EINTR。  

使用场景:

   sigsuspend() 函数可以更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞,使用这种技术可以保护不希望由信号中断的代码临界区。

   如果希望对一个信号解除阻塞,然后pause等待以前被阻塞的信号发生,那么必须使用 sigsuspend() 函数, pause() 函数无法达成上述目的.

  • 阻塞信号
    if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        err_sys("SIG_BLOCK error");
  • 解除阻塞
    if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        err_sys("SIG_SETMASK error");
  • 等待信号
pause();
  • 检查和更改阻塞的信号
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
       /* Prototype for the underlying system call */
//可以根据参数指定的方法修改进程的信号屏蔽字。
//新的信号屏蔽字由参数set(非空)指定,而原先的信号屏蔽字将保存在oset(非空)中。
//如果set为空,则how没有意义,但此时调用该函数,如果oset不为空,则把当前信号屏蔽字保存到oset中。
 
/* 底层系统调用的原型 */
int rt_sigprocmask(int how, const kernel_sigset_t *set,kernel_sigset_t *oldset, size_t sigsetsize);
       /* Prototype for the legacy system call (deprecated) */
 
 
int sigpending(sigset_t *set);
//获取信号集,查询被搁置的信号

参数:

how:不同取值及操作如下所示:

注:调用这个函数才能改变进程的屏蔽字,之前的函数都是为改变一个变量的值而已,并不会真正影响进程的屏蔽字。

SIG_BLOCK :    附加set到阻塞表,原来的保存在到oldset

SIG_UNBLOCK:从阻塞表中删除set中的信号,原来的保存到oldset

SIG_SETMASK:清空阻塞表并设置为set,原来的保存到oldset

返回值:

       若成功,返回0

       若出错(how取值无效返回-1),返回-1,并设置errno为EINVAL。

目录
相关文章
|
7天前
|
Linux 应用服务中间件 Shell
linux系统服务二!
本文详细介绍了Linux系统的启动流程,包括CentOS 7的具体启动步骤,从BIOS自检到加载内核、启动systemd程序等。同时,文章还对比了CentOS 6和CentOS 7的启动流程,分析了启动过程中的耗时情况。接着,文章讲解了Linux的运行级别及其管理命令,systemd的基本概念、优势及常用命令,并提供了自定义systemd启动文件的示例。最后,文章介绍了单用户模式和救援模式的使用方法,包括如何找回忘记的密码和修复启动故障。
27 5
linux系统服务二!
|
7天前
|
Linux 应用服务中间件 Shell
linux系统服务!!!
本文详细介绍了Linux系统(以CentOS7为例)的启动流程,包括BIOS自检、读取MBR信息、加载Grub菜单、加载内核及驱动程序、启动systemd程序加载必要文件等五个主要步骤。同时,文章还对比了CentOS6和CentOS7的启动流程图,并分析了启动流程的耗时。此外,文中还讲解了Linux的运行级别、systemd的基本概念及其优势,以及如何使用systemd管理服务。最后,文章提供了单用户模式和救援模式的实战案例,帮助读者理解如何在系统启动出现问题时进行修复。
26 3
linux系统服务!!!
|
1天前
|
机器学习/深度学习 自然语言处理 Linux
Linux 中的机器学习:Whisper——自动语音识别系统
本文介绍了先进的自动语音识别系统 Whisper 在 Linux 环境中的应用。Whisper 基于深度学习和神经网络技术,支持多语言识别,具有高准确性和实时处理能力。文章详细讲解了在 Linux 中安装、配置和使用 Whisper 的步骤,以及其在语音助手、语音识别软件等领域的应用场景。
12 5
|
1天前
|
缓存 运维 监控
【运维必备知识】Linux系统平均负载与top、uptime命令详解
系统平均负载是衡量Linux服务器性能的关键指标之一。通过使用 `top`和 `uptime`命令,可以实时监控系统的负载情况,帮助运维人员及时发现并解决潜在问题。理解这些工具的输出和意义是确保系统稳定运行的基础。希望本文对Linux系统平均负载及相关命令的详细解析能帮助您更好地进行系统运维和性能优化。
12 3
|
1天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####
|
7天前
|
网络协议 Linux
linux系统重要文件目录
本文介绍了Linux系统中的重要目录及其历史背景,包括根目录、/usr、/etc、/var/log和/proc等目录的结构和功能。其中,/etc目录下包含了许多关键配置文件,如网卡配置、DNS解析、主机名设置等。文章还详细解释了各目录和文件的作用,帮助读者更好地理解和管理Linux系统。
25 2
|
9天前
|
Ubuntu Linux Shell
Linux 系统中的代码类型或脚本类型内容
在 Linux 系统中,代码类型多样,包括 Shell 脚本、配置文件、网络配置、命令行工具和 Cron 定时任务。这些代码类型广泛应用于系统管理、自动化操作、网络配置和定期任务,掌握它们能显著提高系统管理和开发的效率。
|
11天前
|
关系型数据库 MySQL Linux
Linux系统如何设置自启动服务在MySQL数据库启动后执行?
【10月更文挑战第25天】Linux系统如何设置自启动服务在MySQL数据库启动后执行?
59 3
|
13天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
14天前
|
存储 安全 关系型数据库
Linux系统在服务器领域的应用与优势###
本文深入探讨了Linux操作系统在服务器领域的广泛应用及其显著优势。通过分析其开源性、安全性、稳定性和高效性,揭示了为何Linux成为众多企业和开发者的首选服务器操作系统。文章还列举了Linux在服务器管理、性能优化和社区支持等方面的具体优势,为读者提供了全面而深入的理解。 ###
下一篇
无影云桌面