首页 > 系统相关 >Linux环境编程day04--信号产生与处理

Linux环境编程day04--信号产生与处理

时间:2023-08-05 09:33:06浏览次数:36  
标签:set -- 信号处理 day04 int 信号 Linux 进程 void

信号管理

基本概念

1、中断
当进程接收到消息后中止当前正在进行进程,转而去执行其它任务,等其它任务执行结束后再返回刚刚中止的位置,可以继续往下运行
这种执行模式称为中断
中断分为硬件中断、软件中断,硬件中断是由硬件设备引发的、软件中断是执行了中断指令引发
2、信号
信号是一种软件中断,由操作系统发出,进程接收后会执行相应的操作
3、常见信号
kill -l 显示所有信号
SIGINT(2) Ctrl+c 终止
SIGQUIT(3) Ctrl+\ 终止+core
SIGFPE(8) 除0 终止+core
SIGKILL(9) 终止信号 终止
SIGSEGV(11) 非法访问内存 终止+core
4、不可靠信号和可靠信号
建立在早期的信号处理机制上的信号称为不可靠信号(1-31)
不支持排队,可能会丢失,如果同一个信号连续多次发送,很可能进程只接受到一次
建立在新的信号处理机制上的信号称为可靠信号(34-64)
支持排队,不会丢之
5、信号的来源
硬件异常:除零、非法访问内存、未定义指令、总线错误
软件异常:通过一些命令、函数产生信号
6、信号的处理方式
1、忽略
2、终止进程
3、终止进程并产生core文件
4、捕获并处理
在信号来之前先向内核注册一个信号处理函数与,要捕获的信号绑定当信号发生时进程会中止先转去执行信号处理函数
7、命令发送信号
kill 信号编号(宏名) 进程id(pid)

信号捕获

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:向内核注册一个信号处理函数
signum:要绑定捕获的信号编号
handler:函数指针 提供需要注册的信号处理函数
亦可以使用以下参数
SIG_IGN 忽略处理
SIG_DFL 按默认方式处理
返回值:
之前的信号处理方式
注意:只有9 、19 号信号不能被捕获、也不能忽略
注意:有些系统通过signal注册的函数只能有效一次,第一次之后会还原成默认的处理方式,可以在信号处理函数的末尾重新signal注册
注意:信号处理函数结束后会返回信号产生时的代码处继续执行,如果导致信号产生的错误还在,例如段错误、除零等,可能会导致死循环反复调用信号处理函数,正确的处理方式是备份进程数据然后结束进程(exit)
注意:通过fork创建的子进程会继承父进程的信号处理方式,但是通过exec系列函数创建的子进程会恢复默认的信号处理方式

信号的产生

1、键盘
Ctrl+C Ctrl+\ Ctrl+z暂停\挂起 fg继续
2、错误
段错误 除0 硬件故障
3、命令
kill -信号id 进程号
killall -信号id 进程名 向同进程名的所有进程发送信号
4、函数
int kill(pid_t pid, int sig);
功能:向进程号pid的进程发送信号sig
int raise(int sig);
功能:向自己发送信号sig
void abort(void);
功能:向自己发送SIGABRT信号
unsigned int alarm(unsigned int seconds);
功能:让内核在seconds秒后向自己发送SIGALRM信号
返回值:上一次alarm设置的剩余秒数
注意:再次调用alarm函数会重置闹钟时间,不会产生两次信号

进程休眠

unsigned int sleep(unsigned int seconds);
功能:让调用进程进入指定的休眠秒数,秒数到了会唤醒,并且在休眠中遇到了正常的信号都会提前唤醒返回
返回值:剩余没睡的秒数
int pause(void);
功能:让进程进入休眠,直到遇到正常的信号才唤醒
返回值:要么一直休眠不返回,要么返回-1表示信号来了

信号集和信号阻塞

信号集:是一种数据类型,定义变量可以存储多个信号
sigset_t 128位二进制数 用每一位代表一个信号
相关的函数:
int sigemptyset(sigset_t *set);
功能:情空信号集set
int sigfillset(sigset_t *set);
功能:填满信号集set
int sigaddset(sigset_t *set, int signum);
功能:向信号集set中添加信号signum
int sigdelset(sigset_t *set, int signum);
功能:从信号集set中删除信号signum
int sigismember(const sigset_t *set, int signum);
功能:测试信号集set中是否存在信号signum
返回值:
1 存在
0 不存在
-1 非法信号
信号阻塞:
当进程正在执行一些关键性的特殊操作时,不适合暂停去处理信号,此时可以让内核先屏蔽信号,等特殊操作完成后再继续发送并处理
当信号产生时,内核会在其维护的一张信号表中给对应的进程设置一个该信号的标记,整个过程称为递送
从信号产生到完成递送的过程有一个时间间隔,处于该间隔中的信号状态称为未决
信号阻塞屏蔽是让信号处于未决状态,暂停递送,当解除阻塞时处于未决状态的信号就会继续递送
每个进程中都有一个信号集用于记录该进程中要屏蔽的信号
int sigprocmask(int how,const sigset_t *set,sigset_t *oldset);
功能:设置进程的信号屏蔽集
how: 设置信号屏蔽的方式
SIG_BLOCK 把set中的信号添加到本进程的信号屏蔽集中
SIG_UNBLOCK 从信号屏蔽集中删除set中的信号
SIG_SETMASK 用set完全替换原来的信号屏蔽集
set:想要设置的信号集
oldset:获取设置前信号屏蔽集

附带信息的信号处理函数

int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
功能:向内核注册一个信号处理函数
signum:想要绑定的信号
act:要注册的信号处理函数

    struct sigaction {
        void     (*sa_handler)(int);//不带信息的信号处理函数
        void     (*sa_sigaction)(int, siginfo_t *, void *);
        //  附带额外信息的信号处理函数
        sigset_t   sa_mask;
        //  信号屏蔽集,如果有想要屏蔽的信号,可以给该成员赋值
        int        sa_flags;
        //  信号绑定的处理标志
            SA_SIGINFO  使用sa_sigaction来绑定
            SA_NODEFER  在信号处理过程中绑定的信号不会被屏蔽
            SA_RESETHAND 该信号处理方式执行一次后,还原会默认的信号处理方式
            SA_RESTART  绑定的信号执行完处理函数后,被中断的系统调用会重新启动
        void     (*sa_restorer)(void);  //保留NULL
    };

int sigqueue(pid_t pid, int sig, const union sigval value);
功能:向进程pid发送附带额外数据信息的信号sig
union sigval {
int sival_int; // 整数
void *sival_ptr; // 指针
};

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

void sigint_data(int num, siginfo_t* info, void* ptr)
{
    printf("附带信息%s的信号%d来了 信号发送者是%u\n",(char*)info->si_ptr,num,info->si_pid);    
}

int main(int argc,const char* argv[])
{
    pid_t pid = getpid();

    struct sigaction act = {};
    act.sa_sigaction = sigint_data;
    act.sa_flags = SA_SIGINFO;
    sigaction(SIGINT,&act,NULL);

    sleep(3);
    union sigval value;
    value.sival_ptr = "呵呵";
    sigqueue(pid,SIGINT,value);

    for(;;);
}

定时器

int getitimer(int which, struct itimerval *curr_value);
功能:获取当前进程的定时方案
which:
ITIMER_REAL 真实定时器 程序的总运行时间 SIGALRM
ITIMER_VIRTUAL 虚拟定时器 用户态的运行时间 SIGVTALRM
ITIMER_PROF 实际定时器 用户态+内核态的运行时间 SIGPROF
真实定时器 = 实际定时器+切换时间+休眠时间
curr_value:定时方案
struct itimerval {
struct timeval it_interval; // 定时间的间隔时间
struct timeval it_value; // 第一次启动定时器的时间
};
struct timeval {
time_t tv_sec; // 秒
suseconds_t tv_usec; // 微秒
};
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
功能:设置定时器
new_value:想要设置的定时方案
old_value:获取旧的定时方案

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>

void sigalrm(int num)
{
    printf("定时器时间到啦\n");    
}

int main(int argc,const char* argv[])
{
    signal(SIGALRM,sigalrm);
    //    设置定时方案
    struct itimerval value = {{1,500000},{5,500000}};
    printf("%d\n",setitimer(ITIMER_REAL,&value,NULL));
    for(;;);
}


标签:set,--,信号处理,day04,int,信号,Linux,进程,void
From: https://www.cnblogs.com/bigflyny/p/17607510.html

相关文章

  • 前后端联调步骤
    确定接口:前后端需要确定接口的格式和参数。可以使用RESTfulAPI或其他协议来定义接口。模拟数据:前端可以使用mock数据来模拟后端接口的数据,以便在没有实际数据的情况下进行测试。联调接口:前后端开始通过接口协作来实现整个应用的功能。后端提供接口,前端调用接口获取数据。......
  • yapi安装及使用
    yapi介绍YApi是一款高效、易用、功能非常强大的api可视化接口管理平台,旨在为互联网公司的技术人员提供更优雅的接口管理服务系统。它可以帮助开发者快速创建、发布、维护API接口,并且YApi为用户提供了优秀的交互体验,技术人员只需利用平台提供的接口数据写入工具以及很少的点击......
  • 应用不停服,平滑升级分库分表还能这样做
    背景分库分表是大型互联网应用经常采用的一种数据层优化方案,常见的分库分表中间件如sharding-jdbc、mycat都已经比较成熟,基本上可以应对我们一般的分库分表需求。做过分库分表的同学应该知道,在给业务系统做分库分表改造过程中,难的不是如何使用这些组件进行分库分表,......
  • sql注入发现
    1、异常YouhaveanerrorinyourSQLsyntax;checkthemanualthatcorrespondstoyourMySQLserverversionfortherightsyntaxtousenear''1'''atline1一般适用于查询输出的场景,而对于盲注场景和其它sql语句类型,基本不会输出sql异常。......
  • nflsoj 1351 抓住奶牛
    这题类似走迷宫,走迷宫是向四个方向进行拓展,而这道题好比是向三个方向拓展,分别是:\(x+1,x-1,x×2\)在这里拓展的时候我写了一个函数operation来计算拓展后的坐标这里判断坐标是否合法的时候我取了最大值的两倍加5,因为坐标不一定在\(k\)的左边,有可能超出去了再往回走,不过超出一......
  • P4850 [IOI2009] Raisins 题解
    前言:IOI还出这样水的纯记忆化搜索题?还是T4?真令人难以置信。题意:题目传送门一个N×M的矩阵,对于任意一个子矩阵,只能横着或竖着分割,并且分割一次的价值为改子矩阵的元素之和,现要将该矩阵分割成1×1的方格,求最小的分割总价值之和。思路:看到这是个最优化的题,且数据范围很......
  • MVVM --- 实现多层级通知
    引言在实际开发场景中,当ViewModel内的一个属性是一个ObservableCollection<T>或者是一个多层级class的时候,有可能有的需求需要ObservableCollection<T>内的元素的子属性或多层级class的子属性,甚至子属性的子属性,变化,需要通知到ViewModel,该怎么做呢?例如我有一个设置功能模......
  • 论文解读(MCD)《Maximum Classifier Discrepancy for Unsupervised Domain Adaptation》
    Note:[wechat:Y466551|付费咨询,非诚勿扰]论文信息论文标题:MaximumClassifierDiscrepancyforUnsupervisedDomainAdaptation论文作者:KuniakiSaito,KoheiWatanabe,Y.Ushiku,T.Harada论文来源:2018CVPR论文地址:download论文代码:download视屏讲解:click1介绍 ......
  • UVA11732 "strcmp()" Anyone?
    UVA11732"strcmp()"Anyone?题目传送门一个我认为比较有趣的问题……题意给出\(n\)个字符串,两两比较字典序大小,求出所需比较的总次数并输出。分析使用trie树(字典树)来统计给定字符串集合中所有字符串的前缀子串出现次数之和。trie树是一种多叉树数据结构,用于高效地存......
  • 应用不停服,平滑升级分库分表还能这样做
    背景分库分表是大型互联网应用经常采用的一种数据层优化方案,常见的分库分表中间件如sharding-jdbc、mycat都已经比较成熟,基本上可以应对我们一般的分库分表需求。做过分库分表的同学应该知道,在给业务系统做分库分表改造过程中,难的不是如何使用这些组件进行分库分表,......