首页 后端开发 php教程 Linux--信号

Linux--信号

Jan 18, 2017 am 10:28 AM

一、信号
信号用来通知进程发生了异步事件。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。

**用kill-l 命令查看系统定义的信号列表

二、信号的产生方式
① 通过键盘组合键向前台发送信号,(一个命令后面加 & 可以发到后台运行)

a.信号的默认动作是终止进程,SIGQUIT的默认处理动作是终止进程并且Core Dump,(core dump是进程异常终止时,可以选择把进程的用户空间内存数据全部保存到磁盘上,文件名通常是core,这就叫做 core dump,通常就是程序有了BUG,可以用调试器检查core文件以查清错误原因,)默认是不允许产生core文件的,因为core文件中可能包含用户密码,不安全,在开发调试时可以用 ulimit命令改变这个限制,允许产生core文件。
用命令 ulimit -c 1024

ulimit命令改变了Shell进程的Resource Limit,test进程的PCB由Shell进程复制而来,所以也具有和Shell进程相同的Resource Limit值,这样就可以产生Core Dump了
② 通过调用系统函数想进程发送信号

a.kill命令是调用kill函数实现的。kill函数可以给一个指定的进程发送指定的信号.raise函数可以给当前进程发送指定的信号(自己给自己发信号). 
int kill(pid_t pid, int signo);
int raise(int signo);
都是成功返回0,错误返回-1;

abort函数使当前进程接收到SIGABRT信号而异常终止。
void abort(void);

像exit函数一样,abort函数总会成功的,所以没有返回值。

③ 由软件条件产生的信号

a.alarm函数 和SIGALRM信号
unsigned int alarm(unsigned int seconds);调用alarm函数可以设定一个闹钟,就是告诉内核在senconds秒后给当前进程发SIGALRM信号,默认动作是终止当前进程,函数的返回值是0或者是以前设定的闹钟时间还余下的秒数。
三、处理信号的方式
① 忽略此信号

② 执行信号的默认处理动作,一般是终止进程

③ 捕捉信号

四、信号的递达和阻塞
①、阻塞

实际执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞(Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。阻塞和忽略是不一样的只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
信号在内核中的表示

316.jpg

每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志
如果在进程解除对某信号的阻塞之前这种信号产生过多次,在Linux中常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。每个信号只有一 个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。(blank是一种状态,pending表示的是有无)未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。
②、信号集操作函数 

#include <signal.h>
int sigemptyset(sigset_t *set);//初始化对应的信号集bit位为0
int sigfillset(sigset_t *set);//初始化对象的信号集bit位为1
int sigaddset(sigset_t *set, int signo);//添加有效信号 
int sigdelset(sigset_t *set, int signo);//删除有效信号
int sigismember(const sigset_t *set, int signo);//判断一个信号集的有效信号中是否包含某种信号,包含返回1,不包含返回0。
登录后复制

③、sigprocmask

调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);成功则为0,出错则为-1;
如果调用sigprocmask解除了对当前若干个未决信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达.
how参数的含义

SIG_BLOCK set包含了我们希望添加到当前信号屏蔽字的信号,

SIG_UNBLOCK set包含了我们希望从当前信号屏蔽在字中解除阻塞的信号,

SIG_SETMASK 设置当前信号屏蔽字为set所指向的值,

④、sigpending
int sigpending(sigset_t *set);
sigpending读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
用程序说明

#include<stdio.h>  
  2 #include<unistd.h>  
  3 #include<signal.h>  
  4 void printsigset(sigset_t* sig)  
  5 {  
  6     int i=0;  
  7     for(;i<31;i++)  
  8     {  
  9         if(sigismember(sig,i))//判断指定信号是否在目标集合中  
 10         {  
 11             printf("1");  
 12         }  
 13         else  
 14         {  
 15             printf("0");  
 16         }  
 17     }  
 18     printf("\n");  
 19 }  
 20 int main()  
 21 {  
 22     sigset_t s,p;//定义信号集  
 23     sigemptyset(&s);//初始化  
 24     sigemptyset(&p);  
 25     sigaddset(&s,SIGINT);//设置信号ctrl+C  
 26     sigprocmask(SIG_BLOCK,&s,NULL);//设置阻塞信号集,阻塞 SIGINT信号  
 27     while(1)  
 28     {  
 29         sigpending(&p);//获取未决信号集  
 30         printsigset(&p);  
 31         sleep(1);  
 32     }  
 33     return 0;  
 34 }
登录后复制

317.jpg

结果分析:
程序运行时,每秒钟把各信号的未决状态打印一遍,直到按Ctrl-C将会使SIGINT信号处于未决状态,
五、捕捉信号
a.内核如何实现信号的捕捉

如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号,处理过程如下,举例来说明
1. 用户程序注册了SIGQUIT信号的处理函数sighandler。
2. 当前正在执行main函数,这时发生中断或异常切换到内核态。
3. 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。
4. 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函 数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。
5. sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。
6. 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了
**(先从用户态―>内核态->返回用户态之前检查有信号递达,返回用户态处理信号->处理完成后再进入内核态->如果没有新的信号递达,返回用户态恢复上下文继续执行)
b.sigaction
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回- 1
将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函 数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。
当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么它会被阻塞到当前处理结束为止。
如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。
c.pause
int pause(void);
pause函数使调用进程挂起直到有信号递达。如果信号的处理动作是终止进程,则进程终止,pause函数没有机会返回;如果信号的处理动作是忽略,则进程继续处于挂起状态,pause不返回;如果信号的处理动作是捕捉,则调用了信号处理函数之后pause返回-1,
用alarm和pause实现sleep(3)的函数

1 #include<stdio.h>  
 2 #include<unistd.h>  
 3 #include<signal.h>  
 4 void sig_alarm(int signo)  
 5 {  
 6        //do nothing  
 7 }  
 8 unsigned int  my_sleep(unsigned int times)  
 9 {  
 10     struct sigaction new ,old;  
 11     unsigned int unslept=0;  
 12     new.sa_handler=sig_alarm;  
 13     sigemptyset(&new.sa_mask);  
 14     sigemptyset(&old.sa_mask);  
 15     new.sa_flags=0;  
 16     sigaction(SIGALRM,&new,&old);//注册信号处理函数  
 17     alarm(times); //设置闹钟  
 18     pause();  
 19     unslept=alarm(0);//取消闹钟  
 20     sigaction(SIGALRM,&old,NULL);//恢复默认信号处理动作  
 21     return unslept;  
 22 }  
 23 int main()  
 24 {  
 25     while(1)  
 26     {  
 27         my_sleep(5);  
 28         printf("5 senconds pass\n");  
 29     }  
 30     return 0;  
 31 }
登录后复制

六、可重入函数 
当捕捉到信号时,不论进程的主控制流程当前执行到哪儿,都会先跳到信号处理函数中执行,从信号处理函数返回后再继续执行主控制流程。信号处理函数是一个单独的控制流程,因为它和主控制流程是异步的,二者不存在调用和被调用的关系,并且使用不同的堆栈空间。引入了信号处理函数使得一个进程具有多个控制流程,如果这些控制流程访问相同的全局资源(全局变量、硬件资源等),就有可能出现冲突。

以上就是Linux--信号的内容,更多相关内容请关注PHP中文网(www.php.cn)!


本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何解决Linux终端中查看Python版本时遇到的权限问题? 如何解决Linux终端中查看Python版本时遇到的权限问题? Apr 01, 2025 pm 05:09 PM

Linux终端中查看Python版本时遇到权限问题的解决方法当你在Linux终端中尝试查看Python的版本时,输入python...

在Docker环境中使用PECL安装扩展时为什么会报错?如何解决? 在Docker环境中使用PECL安装扩展时为什么会报错?如何解决? Apr 01, 2025 pm 03:06 PM

在Docker环境中使用PECL安装扩展时报错的原因及解决方法在使用Docker环境时,我们常常会遇到一些令人头疼的问�...

如何在LAMP架构下高效整合Node.js或Python服务? 如何在LAMP架构下高效整合Node.js或Python服务? Apr 01, 2025 pm 02:48 PM

在LAMP架构下整合Node.js或Python服务许多网站开发者都面临这样的问题:已有的LAMP(Linux Apache MySQL PHP)架构网站需要...

在Linux终端中使用python --version命令时如何解决权限问题? 在Linux终端中使用python --version命令时如何解决权限问题? Apr 02, 2025 am 06:36 AM

Linux终端中使用python...

Beyond Compare同步Windows和Linux文件时,大小写敏感性失效怎么办? Beyond Compare同步Windows和Linux文件时,大小写敏感性失效怎么办? Apr 01, 2025 am 08:06 AM

BeyondCompare文件比较与同步的难题:大小写敏感性失效在使用Beyond...

如何在macOS上将apscheduler定时任务配置为服务? 如何在macOS上将apscheduler定时任务配置为服务? Apr 01, 2025 pm 06:09 PM

在macOS上将apscheduler定时任务配置为服务在macOS平台上,如果你想将apscheduler定时任务配置为一个服务,类似于ngin...

Linux系统自带Python解释器能删除吗? Linux系统自带Python解释器能删除吗? Apr 02, 2025 am 07:00 AM

关于Linux系统自带Python解释器的删除问题许多Linux发行版在安装时会预装Python解释器,它并非通过软件包管理器�...

c语言多线程的四种实现方式 c语言多线程的四种实现方式 Apr 03, 2025 pm 03:00 PM

语言多线程可以大大提升程序效率,C 语言中多线程的实现方式主要有四种:创建独立进程:创建多个独立运行的进程,每个进程拥有自己的内存空间。伪多线程:在一个进程中创建多个执行流,这些执行流共享同一内存空间,并交替执行。多线程库:使用pthreads等多线程库创建和管理线程,提供了丰富的线程操作函数。协程:一种轻量级的多线程实现,将任务划分成小的子任务,轮流执行。

See all articles