Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1723915
  • 博文数量: 98
  • 博客积分: 667
  • 博客等级: 上士
  • 技术积分: 1631
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-27 15:59
个人简介

一沙一世界 一树一菩提

文章分类

全部博文(98)

文章存档

2021年(8)

2020年(16)

2019年(8)

2017年(1)

2016年(11)

2015年(17)

2014年(9)

2013年(4)

2012年(19)

2011年(1)

2009年(4)

分类: C/C++

2015-07-13 18:56:51

这几天看陈硕的《多线程服务器编程》看到signalfd这一段,写了例子了看了效果,还不错,比sigaction方便。下面具体说说这个signalfd的用法。

一个进程可以使用sigaction或signal改变信号的处理方式。使用这些系统调用,一个进程可以选择以下行为之一在信号递送时触发:执行默认动作;忽略信号;用信号处理程序捕获信号。一个程序定义的函数将在递送对应信号时自动触发。
信号处理方式是一个进程属性,多线程应用下,指定信号的处理方式对于所有线程都是一样的。多线程当中对信号的处理可以参考apue中的说法。基本可以认为是sigprocmask+sigwait,或者sigprocmask+pipe方式。

signalfd是把信号的处理以文件描述符的方式来进行,这样,异步的问题就不用考虑了,也不用使用pipe统一信号源了。直接用即可。
signalfd()返回一个文件描述符,它可用于读取递送给调用者的信号信息。每次从文件描述符read都将阻塞,直到signalfd调用时指定的的信号集内的信号之一递送给调用者。read返回的后缓冲区内包含一个描述信号的结构。

关于具体的意思,请man了解,下面是我的测试代码:


#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/signalfd.h>
#include <pthread.h>


#define handle_error(msg) \
do{perror(msg); exit(EXIT_FAILURE);}while(0)

void *fun1(void *arg)
{
int sigfd1, len1;
struct signalfd_siginfo siginfo;
sigset_t mask;

sigemptyset(&mask);
sigaddset(&mask, SIGINT);
// sigaddset(&mask, SIGQUIT);

sigfd1 = signalfd(-1, &mask, 0);
if(-1 == sigfd1)
handle_error("thread1:sigfd");
while(1)
{
len1 = read(sigfd1, &siginfo, sizeof(siginfo));
if(len1 != sizeof(siginfo))
handle_error("thread1:read");

if(siginfo.ssi_signo == SIGINT)
printf("thread1:got SIGINT\n");
else if(siginfo.ssi_signo == SIGQUIT)
{
printf("thread1:got SIGQUIT\n");
// exit(EXIT_SUCCESS);
}
else
printf("thread1:other signo\n");
}
}

void *fun2(void *arg)
{
int sigfd2, len2;
struct signalfd_siginfo siginfo;
sigset_t mask;

sigemptyset(&mask);
// sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);

sigfd2 = signalfd(-1, &mask, 0);
if(-1 == sigfd2)
handle_error("thread2:sigfd");
while(1)
{
len2 = read(sigfd2, &siginfo, sizeof(siginfo));
if(len2 != sizeof(siginfo))
handle_error("thread2:read");

if(siginfo.ssi_signo == SIGINT)
printf("thread2:got SIGINT\n");
else if(siginfo.ssi_signo == SIGQUIT)
{
printf("thread2:got SIGQUIT\n");
// exit(EXIT_SUCCESS);
}
else
printf("thread2:other signo\n");
}

}
int main(int argc, char *argv[])
{
sigset_t mask;

int ret, signal_fd;
struct signalfd_siginfo sigfd_info;
ssize_t s;

pthread_t tid1, tid2;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);


if(sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
handle_error("sigprocmask");

ret = pthread_create(&tid1, NULL, fun1, NULL);
if(ret != 0)
handle_error("pthread_create1");
ret = pthread_create(&tid2, NULL, fun2, NULL);
if(ret != 0)
handle_error("pthread_create2");

while(1)
{
/*
s = read(signal_fd, &sigfd_info, sizeof(sigfd_info));
if(s != sizeof(sigfd_info))
handle_error("read");


if(sigfd_info.ssi_signo == SIGINT)
printf("got SIGINT\n");
else if(sigfd_info.ssi_signo == SIGQUIT)
{
printf("got SIGQUIT\n");
exit(EXIT_SUCCESS);
}
else
printf("other signo\n");
*/
sleep(10);
printf("main thread run here\n");
}

}
这个函数使man的示例代码,我自己修改的。对信号的处理不完美,一旦运行,就退出不了,可以top aux,然后找到程序的进程号,然后kill掉
两个线程,分别等待一个信号,屏蔽另外的一个信号,主线程两个信号都屏蔽。3个注意点:
1 线程对信号传递的影响,大家可以试试看把信号屏蔽去掉,包括主线程或者子线程,看看什么结果;
2 read的时候,注意信号接收的缓存区要大于struct signalfd_siginfo。
3 如果实际使用当中,要接收什么信号,或者要对什么信号进行捕获的话,在建立新线程前记得sigprocmask,然后再进行其它的。
阅读(4049) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~