2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,
1信号产生原因
2.进程处理信号行为
manpage里信号3中处理方式:
SIG_IGN
SIG_DFL 默认Term动作
a signal handling function
进程处理信号
A默认处理动作
term 中断
core core(调试的时候产生)
gcc –g file.c
ulimit –c 1024
gdb a.out core
ign 忽略
stop 停止
cont 继续
B忽略
C捕捉(用户自定义处理函数)
3信号集处理函数
sigset_t为信号集,可sizeof(sigset_t)查看
将信号集里面的每位都置0
int sigemptyset(sigset_t *set)
将所有信号集都置1
int sigfillset(sigset_t *set)
添加一个信号,也就是将Block阻塞信号集里面的某一位置成1
int sigaddset(sigset_t *set, int signo)
将信号集中某一位取消置1
int sigdelset(sigset_t *set, int signo)
测试某个信号集中的信号是否为1
int sigismember(const sigset_t *set, intsigno)
4 PCB的信号集
信号在内核中的表示示意图
如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允
许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只
计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信
号。从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少
次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t
来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,
在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有
效”和“无效”的含义是该信号是否处于未决状态。
阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解
为阻塞而不是忽略。
5sigprocmask
调用函数sigprocmask可以读取或更改进程的信号屏蔽字。
依赖的头文件:
#include <signal.h>
函数声明:
*set是传入的信号,*oset表示原来的信号集是什么,相当于是*set的一个备份
intsigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1
如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。
how参数的含义
SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,相当于mask=mask|set
SIG_UNBLOCK set包含了我们希望从当前信号屏蔽字中解除阻塞的信号,相当于mask=mask&~set
SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,相当于mask=set
6sigpending(未决打印信号)
#include<signal.h>
int sigpending(sigset_t *set)
sigpending读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则
返回-1。
6案例说明:
运行结果:
程序运行时,每秒钟把各信号的未决状态打印一遍,由于我们阻塞了SIGINT信号,按Ctrl-C将会使SIGINT信号处于未决状态,按Ctrl-\仍然可以终止程序,因为SIGQUIT信号没有阻塞。
这时按Ctrl+\结束。
7信号捕捉设定
8.sigaction
#include <signal.h>
int sigaction(int signum, const structsigaction *act,
struct sigaction *oldact);
struct sigaction 定义:
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:早期的捕捉函数
sa_sigaction : 新添加的捕捉函数,可以传参,和sa_handler互斥,两者通过sa_flags选择采用哪种捕捉函数
sa_mask : 在执行捕捉函数时,设置阻塞其它信号,sa_mask| 进程阻塞信号集,退出捕捉函数后,还原回原有的阻塞信号集
sa_flags : SA_SIGINFO 或者0
sa_restorer:保留,已过时。
案例说明:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void do_sig(int num)
{
int n = 5;
printf("I am do_sig\n");
printf("num = %d\n",num);
while(n--)
{
printf("num = %d\n",num);
sleep(1);
}
}
int main(void)
{
struct sigaction act;
act.sa_handler = do_sig;
//act.sa_handler = SIG_DFL;
//act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask,SIGQUIT);
act.sa_flags = 0;
sigaction(SIGINT,&act,NULL);
while(1)
{
printf("**********\n");
sleep(1);
}
return 0;
}
9 C标准库信号处理函数
typedef void (*sighandler_t)(int)
sighandler_t signal(int signum,sighandler_t handler)
int system(const char *command)
system的本质是:集合fork,exec,wait一体
10 可重入函数
A:不含全局变量和静态变量是可重入函数的一个要素
B:可重入函数man 7 signal
C:在信号捕捉函数里应可重入函数
例如:strtok就是一个不可重入函数,因为strtok内部维护了一个内部静态指针,保存上一次切割到的位置,如果信号的捕捉函数中也去调用strtok函数,则会造成切割字符串混乱,应用strtok_r版本,r表示可重入。
11时序竞态
int pause(void)
使调用进程挂起,直到有信号递达,如果递达信号是忽略,则继续挂起
int sigsuspend(const sigset_t *mask)
以通过指定mask来临时解除对某个信号的屏蔽,然后挂起等待,当sigsuspend返回时,进程的信号屏蔽字恢复为原来的值
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
void sig_alrm(int signo)
{
/* nothing to do */
}
unsigned int mysleep(unsigned int nsecs)
{
struct sigaction newact, oldact;
unsigned int unslept;
newact.sa_handler = sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM, &newact, &oldact);
alarm(nsecs);
//在alarm的时候,可能会转到其它程序,这之后永远都执行不到下面的这行,因为信号已经执行过了
pause();
unslept = alarm(0);
sigaction(SIGALRM, &oldact, NULL);
return unslept;
}
int main(void)
{
while(1){
mysleep(2);
printf("Two seconds passed\n");
}
return 0;
}
mysleep的改进版
#include<unistd.h>
#include<signal.h>
#include<stdio.h>
void sig_alrm(int signo)
{
/* nothing to do*/
}
unsigned int mysleep(unsigned int nsecs) {
struct sigaction newact,oldact;
sigset_tnewmask,oldmask,suspmask;
unsigned int unslept;
/*set our handler,saveprevious information*/
newact.sa_handler =sig_alrm;
sigemptyset(&newact.sa_mask);
newact.sa_flags = 0;
sigaction(SIGALRM,&newact,&oldact);
/*block SIGALRM and savecurrent signal mask*/
sigemptyset(&newmask);
sigaddset(&newmask,SIGALRM);
sigprocmask(SIG_BLOCK,&newmask,&oldmask);
alarm(nsecs);
suspmask = oldmask;
/*make sure SIGALRM isn'tblocked*/
sigdelset(&suspmask,SIGALRM);
sigsuspend(&suspmask);/*waitfor any signal to be caught*/
/*some signal has bencaught,SIGALRM is now blocked*/
unslept = alarm(0);
sigaction(SIGALRM,&oldact,NULL);/*resetprevious action*/
/*reset signal mask,whichunblocks SIGALRM*/
sigprocmask(SIG_SETMASK,&oldmask,NULL);
return(unslept);
}
int main(void) {
while(1)
{
sleep(2);
printf("Two secondspassed\n");
}
return 0;
}
2信号处理之:信号产生原因,进程处理信号行为,信号集处理函数,PCB的信号集,sigprocmask()和sigpending(),信号捕捉设定,sigaction,C标准库信号处理函数,可重入函数,相关推荐
- 函数不可访问_关于可重入函数
1 前言 最近在公司维护的项目中碰到一个解决了定位很久的 bug , bug 找到的时候发现犯了很低级的错误--在中断处理函数中调用了 printf 函数,因为中断处理函数的调用了不可重入函数,导致中 ...
- Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
首先区分一下Linux信号跟进程间通信中的信号量,它们的关系就犹如老婆跟老婆饼一样,没有一毛钱的关系. 信号的概念 信号的概念:信号是进程之间事件异步通知的一种方式,属于软中断.比如:红绿灯是一种信号 ...
- Linux系统编程34:进程信号之可重入函数,volatile关键字的作用和SIGHLD
文章目录 (1)可重入函数 (2)volatile关键字 A:背景知识 B:产生的问题 C:volatile关键字 (3)SIGHLD信号 A:复习僵尸进程 B:清理僵尸状态的新方法-SIGCHLD ...
- 进程的挂起以及可重入函数
相关接口 pause 函数用于将进程挂起. 如果信号的处理动作是终止进程, 则进程终止, pause 函数没有返回值; 如果信号的处理动作是忽略, 则进程被挂起, pause函数不返回, 如果 ...
- [ Linux ] 可重入函数,volatile 关键字,SIGCHLD信号
目录 1.可重入函数 2.volatile 2.1从信号角度理解volatile的作用 2.2volatile的作用 3.SIGCHLD信号 3.1SIGCHLD信号的验证 1.可重入函数 在数据结构 ...
- Linux | 可重入函数 | volatile | SIGCHLD信号
文章目录 可重入函数 可重入与线程安全 volatile volatile和const同时修饰变量 SIGCHLD信号 可重入函数 当一个函数可以被两个执行流调用,我们称该函数具有重入特征 如果一个函 ...
- Linux信号编程实践(二) 信号发送函数和可重入函数
在早期的UNIX中信号是不可靠的,不可靠在这里指的是:信号可能丢失,一个信号发生了,但进程却可能一直不知道这一点. 现在Linux 在SIGRTMIN实时信号之前的都叫不可靠信号,这里的不可靠主要是不 ...
- 什么是可重入函数, 不可重入函数? 哪些原因导致函数不可重入?
定义: 在实时系统的设计中,经常会出现多个任务调用同一个函数的情况.如果有一个函数不幸被设计成为这样:那么不同任务调用这个函数时可能修改其他任务调用这个函数的数据,从而导致不可预料的后果.这样的函数是 ...
- 14.线程安全?线程不安全?可重入函数?不可重入函数?
线程安全问题 基本定义 线程安全:简单来说线程安全就是多个线程并发执行同一段代码时,不会出现不同的结果,我们就可以说该线程是安全的: 线程不安全:如果多线程并发执行时会产生不同的结果,则该线程就是不安 ...
最新文章
- Openresty最佳案例 | 第7篇: 模块开发、OpenResty连接Redis
- 罗德里格斯公式推导,以及如何使用cv2.Rodrigues进行旋转矩阵和旋转向量之间的相互转化
- linux访问文档根目录之外的网页_开发文档加载不再卡顿,亿点点提升
- 洛谷P1035 [NOIP2002 普及组] 级数求和
- 电商无线端秋季促销PSD分层海报,大战之前设计师准备好了么?
- 安笙机器人_张翰新戏搭档徐璐!包贝尔要和辛芷蕾演奇幻电影?
- sublime text3 智能提示和自动补全
- MVC4 中使用 Area 和 注意的地方
- 让你页面速度飞起来的前端性能优化方案
- 为什么使用一个变频器控制多个电机?
- 三菱5uplc伺服电机指令_长沙汇川伺服电机型号-川其实业
- BLP防数据泄露安全操作系统:道里云公司参展英特尔北京IDF峰会产品介绍(二)
- 掘地求生是什么游戏 把主播都逼疯的玩个锤子是什么游戏-李廷学
- Unreal教学(10)——放置Actor (Placing Actors)
- The Intriguing Obsession
- 第六章第十三题(数列求和)(Sum series)
- 深入浅出Pytorch函数——torch.arange
- c 语言中整除的意义,整数和整除的意义
- 配置邮件服务器及空邮件服务器
- RG Magic Bullet 15(中英对照)
热门文章
- opencv学习笔记8:类型转换
- JavaScript实现数除以二divideByTwo算法(附完整源码)
- JavaScript实现返回数字的二进制表示中使用的位数bitLength算法(附完整源码)
- boost::log::parse_formatter用法的测试程序
- boost::hana::empty用法的测试程序
- hana::detail::variadic::reverse_apply用法的测试程序
- boost::hana::size用法的测试程序
- boost::geometry::strategy::distance::thomas用法的测试程序
- boost::fusion::insert_range用法的测试程序
- GDCM:将文件封装在RawData中的测试程序