进程捕捉到信号对其进行处理时,进程正在执行的正常序列就被信号处理程序临时中断,它首先执行该信号处理程序中的指令。如果从信号处理程序返回(例如没有调用exit或longjmp),则继续执行在捕捉到信号时进程正在执行的正常指令序列。

1. 在信号处理程序中,我们要保证调用”异步信号安全”的函数,即可重入的函数

不可重入的函数大多(a)已知它们使用静态数据结构。(b)它们调用malloc或free(c)它们是标准I/O函数

2. 由于每个线程只有一个errno变量,所以信号处理程序可能会修改其原先值。因此,所有信号处理程序应当在函数的起始保存errno,结尾恢复errno

3. 每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞传递送到该进程的信号集

信号集signal set

int sigemptyset(sigset_t *set); //初始化由set指向的信号集,清除其中所有信号

int sigfillset(sigset_t *set);       //初始化由set指向的信号集,使其包括所有信号

所有应用程序在使用信号集前,要对该信号集调用sigemptyset或sigfillset一次。

信号集初始化之后,可在该信号中增删特定的信号。

int sigaddset(sigset_t *set,int signo)

int sigdelset(sigset_t *set,int signo)

进程的信号屏蔽字

int sigprocmask(int how,const sigset_t *restrict set, const sigset_t *restrict oset)

Oset若是非空指针,那么进程的当前信号屏蔽字通过oset返回

How的三种取值决定了如何修改当前信号屏蔽字:

SIG_BLOCK : 向当前信号屏蔽字中添加参数set包含的信号

SIG_UNBLOCK : 把当前信号屏蔽字中参数set包含的信号删去

SIG_SETMASK : 把参数set设为进程的信号屏蔽字。

请注意,sigprocmask仅为单线程进程定义的。处理多线程进程中信号的屏蔽使用另一个函数

执行信号的处理程序称为信号递达,信号从产生到递达之间的状态称为信号未决。被阻塞的信号将保持在未决状态,直到进程解决对此信号的阻塞。

int sigpending(sigset_t *set)

Set返回当前的未决信号

信号处理的范式

static int pipefd[];

int signal_module_init()

{
struct sigaction act; //信号处理程序指定为sig_handler
act.sa_handler = sig_handler; //在进入信号处理程序前,把act.sa_mask信号集加到进程的信号屏蔽字中。调用sigfillset把所有信号加入这个信号集。这表示当进入信号处理程序后,阻塞一切信号
sigfillset(&act.sa_mask) if( > sigaction(SIGINT,&act,) ||
> sigaction(SIGCHLD,&act,) ||
...... ) {
write_log("failed to init signal:sigaction()");
return -;
}
return signal_pipe_init();
} static int signal_pipe_init()
{
if( < pipe(pipefd,O_CLOEXEC|O_NONBLOCK) ){
write_log("failed to init pipe");
return -;
}
return ;
} static void sig_handler(int signo)
{
//定义一个数组,将你注册的每个信号的signo映射成一个唯一的字符
static const char sig_chars[NSIG+] = {
[SIGINT] = 'I',
[SIGCHLD] = 'C',
.....
}; char s;
int saved_errno; //保存当前的errno。每个线程仅有一个errno变量,不应让信号处理程序中的errno影响正常流程中的errno。因此我们需要在信号处理程序的起始存储errno,在末尾恢复errno
saved_errno = errno;
s = sig_chars[signo];
write(pipefd[],&s,sizeof(s));
errno = saved_errno; } //然后在Reactor中监听pipefd[0]. 其回调函数如下:
void got_signal(ev)
{
int res,ret;
char c;
int fd = ev->fd;
for(;;){
//fd是非阻塞的
do {
res = read(fd,&c,);
} while(res == - && errno == EINTR); //pipe中没有可读数据
if(res <= ){
break;
} switch(c){
case 'I':
dosomething1();
break;
case 'C':
dosomething2();
break;
......
}
}
return;
}

最新文章

  1. [Computational Advertising] 计算广告学笔记之基础概念
  2. GitHub的三个按钮
  3. 解决ScrollView嵌套ListView,ListView填充容器后,界面自动滚动回顶部的问题
  4. c语言 typedef
  5. web提前做好测试
  6. Eclipse的java代码出错:The import org.apache cannot be resolved
  7. php结合jquery异步上传图片(ajaxSubmit)
  8. Median of Two Sorted Arrays 解答
  9. Mysql-左连接查询条件失效的解决办法
  10. 聊聊RPC及其原理
  11. tomcat部署项目后,war包是否可刪?war包存在必要性!
  12. 让oracle数据库的表的id自动递增
  13. PowerShell工作流学习-6-向脚本工作流添加检查点
  14. 2018.9.22 NOIP模拟赛
  15. [转]WordPress“添加媒体”文件时只显示上传到当前文章的附件图片
  16. 内连接查询输出到datagridView
  17. Debian apt-get 用法
  18. uva 11346 - Probability(概率)
  19. [OI向?] ubuntu下一些常用的技巧
  20. 利用Eric+Qt Designer编写倒计时时钟

热门文章

  1. STL的sort函数是使用什么排序算法的?
  2. flask中使用ajax 处理前端请求 弹框展示
  3. Jenkins+jmeter+ant+Git 持续集成(六、代码提交到Gitlab即自动构建)
  4. 40、扩展原理-BeanDefinitionRegistryPostProcessor
  5. MongoDB 分片管理(一)检查集群状态
  6. Educational Codeforces Round 74
  7. RDMA Programming - Base on linux-rdma
  8. linux经常用的命令
  9. es 修改 mapping 字段类型
  10. zabbix(9)iterms(监控项)