Linux信号透彻分析理解与各种实例讲解( 四 )
解释: 本程序用sigqueue不停的向自身发送信号,并且携带数据 , 数据被放到处理函数的第二个参数siginfo_t结构体中的si_ptr指针 , 当num<10时不再发 。
一般而言 , sigqueue与sigaction配合使用 , 而kill与signal配合使用 。
示例3: 一个进程向另外一个进程发送信号 , 并携带信息
发送端:
#include#include#include#include#includeint main(){union sigval value;value.sival_int=10;if(sigqueue(4403,SIGUSR1,value)==-1){//4403是目标进程pidperror("信号发送失败/n");}sleep(2);} 接收端:
#include#include#include#include#includevoid myhandler(int signo,siginfo_t*si,void *ucontext);int main(){struct sigaction oldact,act;act.sa_sigaction=myhandler;act.sa_flags=SA_SIGINFO|SA_NODEFER;//表示执行后恢复 , 用sa_sigaction指示的处理函数 , 在执行期间仍然可以接收信号sigaction(SIGUSR1,while(1){sleep(2);printf("等待信号的到来/n");}}void myhandler(int signo,siginfo_t *si,void *ucontext){ printf("the value is %d/n",si->si_int);}示例4: sigpending的用法
sigpending(sigset_t *set)将未决信号放到指定的set信号集中去 , 未决信号包括被阻塞的信号和信号到达时但还没来得及处理的信号
#include#include#include#include#includevoid myhandler(int signo,siginfo_t *si,void *ucontext);int main(){struct sigaction oldact,act;sigset_t oldmask,newmask,pendingmask;act.sa_sigaction=myhandler;act.sa_flags=SA_SIGINFO;sigemptyset(//首先将阻塞集合设置为空 , 即不阻塞任何信号//注册信号处理函数sigaction(SIGRTMIN+10,//开始阻塞sigemptyset(sigaddset(printf("SIGRTMIN+10 blocked/n");sigprocmask(SIG_BLOCK,sleep(20);//为了发出信号printf("now begin to get pending mask/n");if(sigpending(}if(sigismember(}sigprocmask(SIG_UNBLOCK,printf("SIGRTMIN+10 unblocked/n");}//信号处理函数void myhandler(int signo,siginfo_t *si,void *ucontext){printf("receive signal %d/n",si->si_signo);} 程序执行:
在另一个shell发送信号:
kill -44 4579
SIGRTMIN+10 blockednow begin to get pending maskSIGRTMIN+10 is in the pending maskreceive signal 44SIGRTMIN+10 unblocked
可以看到SIGRTMIN由于被阻塞所以处于未决信号集中 。
关于基本的信号处理函数就介绍到这了 。
第四部分: 保护临界区不被中断
1. 函数的可重入性
函数的可重入性是指可以多于一个任务并发使用函数 , 而不必担心数据错误 。 相反 , 不可重入性是指不能多于一个任务共享函数 , 除非能保持函数互斥(或者使用信号量 , 或者在代码的关键部分禁用中断) 。 可重入函数可以在任意时刻被中断 , 稍后继续执行 , 而不会丢失数据 。
可重入函数:* 不为连续的调用持有静态数据 。 * 不返回指向静态数据的指针;所有数据都由函数的调用者提供 。 * 使用本地数据 , 或者通过制作全局数据的本地拷贝来保护全局数据 。 * 绝不调用任何不可重入函数 。
不可重入函数可能导致混乱现象 , 如果当前进程的操作与信号处理程序同时对一个文件进行写操作或者是调用malloc() , 那么就可能出现混乱 , 当从信号处理程序返回时 , 造成了状态不一致 。 从而引发错误 。
因此 , 信号的处理必须是可重入函数 。
简单的说 , 可重入函数是指在一个程序中调用了此函数 , 在信号处理程序中又调用了此函数 , 但仍然能够得到正确的结果 。
printf , malloc函数都是不可重入函数 。 printf函数如果打印缓冲区一半时 , 又有一个printf函数 , 那么此时会造成混乱 。 而malloc函数使用了系统全局内存分配表 。
2. 保护临界区不被中断
由于临界区的代码是关键代码 , 是非常重要的部分 , 因此 , 有必要对临界区进行保护 , 不希望信号来中断临界区操作 。 这里通过信号屏蔽字来阻塞信号的发生 。
下面介绍两个与保护临界区不被信号中断的相关函数 。
int pause(void);
int sigsuspend(const sigset_t *sigmask);
pause函数挂起一个进程 , 直到一个信号发生 。
sigsuspend函数的执行过程如下:
(1)设置新的mask去阻塞当前进程
(2)收到信号 , 调用信号的处理函数
(3)将mask设置为原先的掩码
(4)sigsuspend函数返回
可以看出 , sigsuspend函数是等待一个信号发生 , 当等待的信号发生时 , 执行完信号处理函数后就会返回 。 它是一个原子操作 。
保护临界区的中断:
(1)首先用sigprocmask去阻塞信号
(2)执行后关键代码后,用sigsuspend去捕获信号
(3)然后sigprocmask去除阻塞
这样信号就不会丢失了 , 而且不会中断临界区 。
使用pause函数对临界区的保护:
文章插图
- 用户|5G信号有猫腻,又在考验用户的智商?
- 拍照|iPhone12还没捂热13就曝光了,屏幕、信号、拍照均有升级!
- 移植|开发者将移植ARM Mac的Linux系统 但需要得到资金支持
- 高通|为什么iphoneXR和iphoneXS信号不稳定?原因正式被确认,望周知!
- 阻挡|5G的推出真的阻挡了4G 的信号?中国移动正面给出回应
- Linux|知名开发者要把Linux移植到苹果M1 Mac上
- Linux(服务器编程):百万并发服务器系统参数调优
- linux配置nginx定时日志分割
- Linux 之父对 C++ 进行了炮轰,C++不值得推荐?
- Linux信号量(2)-POSIX 信号量
