首页 > 系统相关 >linux中的信号处理器函数

linux中的信号处理器函数

时间:2024-09-30 16:25:33浏览次数:1  
标签:重入 主程序 调用 函数 信号处理器 信号处理 linux

信号处理器函数的设计

常见的两种

信号处理器函数设置全局性标志变量并退出。主程序对此标志进行周期性检查,一旦置位随即采取相应动作。

信号处理器函数执行某种类型的清理动作,接着终止进程或者使用非本地跳转将栈解开并将控制返回到主程序中的预定位置。

设计原则

  • 简洁性

    • 短小精悍:信号处理函数应该尽量简短,以避免长时间占用 CPU,防止信号堆积,保持程序响应
    • 避免复杂操作:不要在信号处理函数中做复杂计算或调用可能阻塞的操作,比如文件读写
  • 可重入性

    • 可重入函数:信号处理函数必须能安全地被多次调用,不会导致数据混乱
    • 避免全局变量:如果使用全局变量,确保它们的操作是安全的,或在信号处理期间不会被修改
  • 同步性

    • 尽量避免共享数据:信号处理函数应尽量不与主程序共享数据,避免数据冲突
    • 使用原子操作:如果必须访问共享数据,使用原子操作确保数据的一致性,防止竞争
  • 安全性

    • 避免非安全函数:只调用那些可以安全在信号处理中使用的函数,例如 signal()、write() 等。避免使用如 printf() 和 malloc() 这类不安全的函数
    • 清晰的信号处理逻辑:确保信号处理逻辑简单明了,避免引发额外的信号

非队列化处理

上一节说过了,当信号处理器函数正在执行时,会阻塞同类信号,避免发生重入现象(即重新进入信号处理函数),然后等执行完后,再执行一次(相当于合并同类的信号了),这就发生了信号丢失的现象,所以无法对信号的产生进行计数

可重入函数

要解释可重入函数为何物,首先需要区分单线程程序和多线程程序。典型 UNIX 程序都具有一条执行线程,贯穿程序始终,CPU 围绕单条执行逻辑来处理指令。而对于多线程程序而言,同一进程却存在多条独立、并发的执行逻辑流。

信号的处理会创建出一条独立(不是并发)于主程序的执行线程

如果同一个进程的多条线程可以同时安全地调用某一函数,那么该函数就是可重入的。此处,“安全”意味着,无论其他线程调用该函数的执行状态如何,函数均可产生预期结果。

简单来说,你可以看成是这个函数被打断然后重新进入,仍旧可以产生预期结果,就是不会有啥影响,这个就是可重入函数了

非可重入函数

非可重入函数就是反过来了,它可能产生的原因有以下几点:

  1. 这句话的意思就是数据的一种竞争,全局和静态的就是共享的资源,大家都去修改,没有约定,就会造成混乱

    更新全局变量或静态数据结构的函数可能是不可重入的。(只用到本地变量的函数肯定是可重入的)

    比如说,malloc和free函数维护的一个针对已释放内存块的链表

  2. 这句话的意思是一个函数多次调用会不断地覆盖上次的结果

    还有一些函数库之所以不可重入,是因为它们使用了经静态分配的内存来返回信息。如果信号处理器用到了这类函数,那么将会覆盖主程序中上次调用同一函数所返回的信息(反之亦然)。

    crypt函数的静态缓冲区(存储返回结果)

  3. 这个其实和竞争类似,就是缓冲区还没来得及刷新就被别人拿去修改了

    将静态数据结构用于内部记账的函数也是不可重入的。其中最明显的例子就是 stdio 函数库成员(printf()、scanf()等),它们会为缓冲区 I/O 更新内部数据结构。

    stdio库中对每个文件流维护的缓冲区

异步信号安全函数

可重入的或者不会被信号处理器函数中断的函数

信号处理器函数内部使用全局变量

  • 对errno的使用

      void handler(int sig)
      {
        int savedErrno;
        savedErrno = errno;
        /*code*/
        errno = savedErrno;
      }
    
  • 使用全局变量
    一般信号处理器函数值设置全局标志,然后主程序对全局标志进行检查,执行相应步骤(同时清除标志)

    保证全局变量读写操作的原子性

      volatile sig_atomic_t flag;
    
    • volatile关键字保证处理器函数访问最新的全局标志,而不是访问寄存器中的缓存值,同时避免编译器的优化
    • sig_atomic_t是一种整型数据类型,它保证读写操作的原子性,比如a++(即a=a+1)这种,即读又写,对应的机器指令不止一条,防止中断在其中产生

终止信号处理器函数

  • 使用_exit函数:只会终止进程,不会进行额外的清理工作,exit在调用_exit之前,会刷新stdio的缓冲区
  • kill发送信号终止进程
  • 从信号处理器函数中执行非本地跳转:??????
  • 使用abort函数终止进程:abort函数成功终止进程后,还会刷新stdio流并将其关闭

系统调用的中断和重启

系统调用被中断后,会设置errno(设置为EINTR)表示失败,这时候可以设置是否重启

  • 手动设置
  #define NO_EINTR(stmt) while((stmt) == -1 && errno == EINTR)
  // read的一个重启
  NO_EINTR(cnt = read(fd, buf, BUF_SIZE);
  • SA_RESTART(sigaction函数的标志):对大部分信号都起作用,自动重启

标签:重入,主程序,调用,函数,信号处理器,信号处理,linux
From: https://www.cnblogs.com/dylaris/p/18441985

相关文章

  • 【linux】linux unable to create new native thread
    1.概述今天遇到一个问题unabletocreatenewnativethread但是看着代码这里应该不会报错,出现这个问题该怎么排查呢?当在Linux系统中出现“unabletocreatenewnativethread”错误时,通常是由于达到了系统可用的进程或线程数量限制导致的。这个错误表示系统无法......
  • 十五、存储过程与函数
    文章目录0.引用1.存储过程概述1.1理解1.2分类2.创建存储过程2.1语法分析3.调用存储过程3.1调用格式3.2代码举例3.3如何调试4.存储函数的使用4.1语法分析4.2调用存储函数4.3代码举例4.4对比存储函数和存储过程5.存储过程和函数的查看、修改、删除5.1......
  • Linux的常用命令
    1、用户操作#创建用户useradd用户名#删除用户userdel用户名-f#强制删除用户-r#删除用户的同时,删除与用户相关的所有文件-fr#联合使用#添加密码passwd用户名#切换用户su用户名2、系统操作2.1系统关机#系统关机shutdown#一分钟之后关机shutdown-h......
  • linux 如何创建定时任务?crontab -e 定时任务使用的时间是系统时间
    crontab-e创建的定时任务使用的是系统时间。什么是系统时间?系统时间是操作系统内部维护的一个时间戳,用于记录系统启动以来经过的时间,以及当前的日期和时间。系统时间通常与硬件时钟同步,以确保时间的准确性。crontab如何使用系统时间?crontab在执行定时任务时,会根据系统......
  • 第29篇 在Linux CentOS系统上部署SqlServer数据库,并实现内网穿透
    在Linuxcentos环境下安装部署sqlserver数据库,并结合cpolar内网穿透工具,创建安全隧道将其映射到公网上,获取公网地址,实现在外异地远程连接家里/公司的sqlserver数据库,而无需公网IP,无需设置路由器,亦无需云服务器。1.安装sqlserver下载SQLServer2022(16.x)RedHat存储库配......
  • linux内核调试痛点之函数参数抓捕记
    1.linux内核调试工具crash并不能直接显示函数参数,而这个对调试又非常重要下面是工作中一个实际的问题,我们的进程hang在如下一个内核栈中了,通过栈回溯可知是打开了一个nfs3的网盘文件或者目录,已知客户机器的NAS盘不可访问了,只要访问就会hang住,但我们的进程理论上是不会访问该NAS......
  • linux gdb debuging
    GDBGNU下的一个调试软件,在linux下可以用来调试c/c++代码。启动可以通过gdb--help查看用法,如下:ThisistheGNUdebugger.Usage:gdb[options][executable-file[core-fileorprocess-id]]gdb[options]--argsexecutable-file[inferior-arguments...]gdb[optio......
  • Linux操作系统如何定时关机?
    在日常使用电脑的过程中,一般都会有软件升级、系统杀毒的工作,可能还需要电脑的定时关机、提醒事项功能。对于Linux操作系统,可以使用几种任务计划工具来指定相应的任务计划,使这些需求自动在后台运行。一、at命令at命令的作用是在一个指定的时间执行任务,且只能执行一次。它的使......
  • 【Linux】Docker下载与使用-nginx
    目录一、Docker介绍     二、Docker结构三、下载Daocker1.在linux上下载docker,执行以下命令即可:2.开启docker3.执行以下操作并进行使用四、在Docker上安装nginx一、Docker介绍             Docker:是给予Go语言实现的开源项目。   ......
  • 用自定义函数镶嵌求解某年某月的天数
    首先分析年份年份分为1.平年2.闰年对于闰年的定义为可以被4整除并且不被100整除,或者可以被400整除部分代码如下​if((y%4==0&&y%100!=0)||y%400==0)//if判断年份是否是闰年​ 月份的判断一年有12个月,1~12个月中天数不同,其中可以用数组来表示自定......