linux c编程:信号(五) sigsuspend

更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞。使用这种技术可以保护不希望由信号中断的代码临界区。如果希望对一个信号解除阻塞,然后pause等待以前被阻塞的信号发生,则又将如何呢?假定信号时SIGINT,实现这一点的一种不正确的方法是:

sigset_t    newmask, oldmask;

sigemptyset(&newmask);

sigaddset(&newmask, SIGINT);

/* block SIGINT and save current signal mask */if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

err_sys("SIG_BLOCK error");

/* critical region of code */if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

err_sys("SIG_SETMASK error");

/* window is open */

pause();    /* wait for signal to occur */

/* continue processing */

如果在信号阻塞时将其发送给进程,那么该信号的传递就被推迟直到对它解除了阻塞。对应用程序而言,该信号好像发生在解除对SIGINT的阻塞和pause之间。如果发生了这种情况,或者如果在解除阻塞时刻和pause之间确实发生了信号,那么就产生了问题。因为我们可能不会再见到该信号,所以从这种意义上而言,在此时间窗口(解除阻塞和pause之间)中发生的信号丢失了,这样就使pause永远阻塞。

为了纠正此问题,需要在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。这种功能是由sigsuspend函数提供的。

#include <signal.h>

int sigsuspend( const sigset_t *sigmask );

返回值:-1,并将errno设置为EINTR

将进程的信号屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

void handler(int sig)   //信号处理程序

{

if(sig == SIGINT)

printf("SIGINT sig");

else if(sig == SIGQUIT)

printf("SIGQUIT sig");

else

printf("SIGUSR1 sig");

}

int main()

{

sigset_t new,old,wait;   //三个信号集

struct sigaction act;

act.sa_handler = handler;

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

sigaction(SIGINT, &act, 0);    //可以捕捉以下三个信号:SIGINT/SIGQUIT/SIGUSR1

sigaction(SIGQUIT, &act, 0);

sigaction(SIGUSR1, &act, 0);

sigemptyset(&new);

sigaddset(&new, SIGINT);  //SIGINT信号加入到new信号集中

sigemptyset(&wait);

sigaddset(&wait, SIGUSR1);  //SIGUSR1信号加入wait

sigprocmask(SIG_BLOCK, &new, &old);       //将SIGINT阻塞,保存当前信号集到old中

//临界区代码执行

if(sigsuspend(&wait) != -1)  //程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1信  号,阻塞掉,程序继续挂起;过来其他信号,例如SIGINT,则会唤醒程序。执行sigsuspend的原子操作。注意:如果“sigaddset(&wait, SIGUSR1);”这句没有,则此处不会阻塞任何信号,即过来任何信号均会唤醒程序。

printf("sigsuspend error");

printf("After sigsuspend");

sigprocmask(SIG_SETMASK, &old, NULL);

return 0;

}

sigsuspend的原子操作是:

(1)设置新的mask阻塞当前进程(上面是用wait替换new,即阻塞SIGUSR1信号)

(2)收到SIGUSR1信号,阻塞,程序继续挂起;收到其他信号,恢复原先的mask(即包含SIGINT信号的)。

(3)调用该进程设置的信号处理函数(程序中如果先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,因为SIGUSR1是前面阻塞的)

(4)待信号处理函数返回,sigsuspend返回了。(sigsuspend将捕捉信号和信号处理函数集成到一起了)

原文地址:https://www.cnblogs.com/zhanghongfeng/p/9153060.html

时间: 2024-10-15 18:53:48

linux c编程:信号(五) sigsuspend的相关文章

嵌入式 Linux系统编程(五)——目录文件函数

嵌入式 Linux系统编程(五)--目录文件函数 Linux中目录也是文件,目录操作函数为标准IO库函数.主要函数如下: #include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); DIR *fdopendir(int fd); 成功返回一个指向目录流的指针,失败返回NULL,并且设置errno全局变量. #include <dirent.h> struct dirent *rea

嵌入式 Linux网络编程(五)——epoll机制

嵌入式 Linux网络编程(五)--epoll机制 一.epoll简介 epoll是在2.6内核中提出的,是select和poll的增强版本.epoll更加灵活,没有描述符限制,使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中. 1.epoll函数 #include <sys/epoll.h> int epoll_create(int size); 创建一个epoll的句柄,size表示监听的文件描述的数量 int epoll_ctl(int epfd,

[linux环境编程] 信号的基本概念与操作函数

[linux环境编程] 信号的基本概念与操作函数 一.基本的概念 1.中断的基本概念 中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂时中断的程序. 而在Linux中通常分为外部中断(又叫硬件中断)和内部中断(又叫异常). 硬中断:来自硬件设备的中断 软中断:来自其它程序的中断 2.信号的基本概念 信号是软件中断,提供了一种处理异步事件的方法,可以把他看作是进

linux网络编程---------信号大讲堂

1. 信号简介 linux系统中无时无该产生着信号.信号在linux上又称软件中断,用来通知进程发生了异步事件.在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的.信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达.进程之间可以互相通过系统调用kill发送软中断信号.内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件.信号机制除了基本通知功能外,还可以传递附

Linux shell 编程(五):数组

数组 数组是有序的元素序列 .若将有限个类型相同的变量的集合命名,那么这个名称为数组名.组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量.用于区分数组的各个元素的数字编号称为下标.数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按无序的形式组织起来的一种形式.这些无序排列的同类数据元素的集合称为数组. 在shell中数组有两种类型: 索引数组(indexed arrays) 关联数组(associative arrays) 索引数组(indexed arrays

Linux环境编程之文件I/O(五):fcntl函数

引言: 对于一个普通的文件,我们可以想到的对它的操作有,读取文件的内容.写数据到文件中,这些都是前面提到的read.write函数的作用.除此之外,还可以获取文件的其他性质,并对这些性质进行修改,比如文件的描述符.文件描述符标记.文件状态标志等等.这些对文件性质的修改就由fcntl函数完成. 函数介绍: #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 参数: fd:

linux系统编程之信号(四)

今天继续探讨信号相关的东东,话不多说,正入正题: 信号在内核中的表示: 下面用图来进一步描述这种信号从产生到递达之间的状态(信号阻塞与未诀): 那是怎么来决定的呢?下面慢慢来举例分解: 所以,通过这些图,可以描述信号从产生到递达的一个过程,上面的理解起来可能有点难,下面会用代码来进一步阐述,在进行实验之前,还需了解一些函数的使用,这些函数在实验中都会被用到,也就是信号集操作函数. 信号集操作函数: 其中解释一下sigset_t,百度百科解释为: 而这个函数的意义就是将这64位清0 这个函数的意义

Linux网络编程 五种I/O 模式及select、epoll方法的理解

Linux网络编程 五种I/O 模式及select.epoll方法的理解 web优化必须了解的原理之I/o的五种模型和web的三种工作模式 五种I/O 模式--阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/OLinux网络编程 五种I/O 模式及select.epoll方法的理解

Linux高性能server编程——信号及应用

?? 信号 信号是由用户.系统或者进程发送给目标进程的信息.以通知目标进程某个状态的改变或系统异常. Linux信号可由例如以下条件产生: 对于前台进程.用户能够通过输入特殊的终端字符来给它发送信号.比方输入Ctrl+C一般会给进程发送一个终端信号. 2.系统异常 系统状态变化 执行kill命令或调用kill函数 Linux信号概述 发送信号 Linux下,一个进程给其它进程发送信号的API是kill函数.其定义例如以下: #include <sys/types.h> #include <