Chinaunix首页 | 论坛 | 博客
  • 博客访问: 265521
  • 博文数量: 107
  • 博客积分: 305
  • 博客等级: 二等列兵
  • 技术积分: 417
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-22 09:42
文章分类

全部博文(107)

文章存档

2014年(3)

2013年(41)

2012年(34)

2011年(28)

2008年(1)

分类:

2011-11-27 20:35:44

原文地址:linux 下信号处理 作者:qqrilxk

linux进程 信号处理相关API介绍:
1. 信号产生
int kill(pid_t pid,int sig);
int raise(int sig);
unisigned int  alarm(unsigned int seconds);

kill系统调用负责向进程发送信号sig.
如果pid是正数,那么向信号sig被发送到进程pid.
如果pid等于0,那么信号sig被发送到所以和pid进程在同一个进程组的进程
如果pid等于-1,那么信号发给所有的进程表中的进程,除了最大的哪个进程号.
如果pid由于-1,和0一样,只是发送进程组是-pid.
我们用最多的是第一个情况.
raise系统调用向自己发送一个sig信号.
alarm函数和时间有点关系了,这个函数可以在seconds秒后向自己发送一个SIGALRM信号.
2. 信号操作
int sigemptyset(sigset_t *set);
int  sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
int sigismember(sigset_t *set,int signo);
int sigprocmask(int how,const sigset_t *set,sigset_t *oset);

sigemptyset函数初始化信号集合set,将set设置为空.sigfillset也初始化信号集合,只是将信号集合设置为所有信号的集合.sigaddset将信号signo加入到信号集合之中,sigdelset将信号从信号集合中删除.sigismember查询信号是否在信号集合之中.
sigprocmask是最为关键的一个函数.在使用之前要先设置好信号集合set.这个函数的作用是将指定的信号集合set加入到进程的信号阻塞集合之中去,如果提供了oset那么当前的进程信号阻塞集合将会保存在oset里面.参数how决定函数的操作方式. 
SIG_BLOCK:增加一个信号集合到当前进程的阻塞集合之中. 
SIG_UNBLOCK:从当前的阻塞集合之中删除一个信号集合. 
SIG_SETMASK:将当前的信号集合设置为信号阻塞集合.
 
3.信号处理
int sigaction(int signo,const struct sigaction *act,
struct sigaction *oact);

struct sigaction {
void (*sa_handler)(int signo);
void (*sa_sigaction)(int siginfo_t *info,void *act);
sigset_t sa_mask;
int  sa_flags;
void (*sa_restore)(void);
        }  

 signo很简单就是我们要处理的信号了,可以是任何的合法的信号.有两个信号不能够使用(SIGKILL和SIGSTOP). act包含我们要对这个信号进行如何处理的信息.oact更简单了就是以前对这个函数的处理信息了,主要用来保存信息的,一般用NULL就OK了. 
信号结构中 sa_handler是一个函数型指针,这个指针指向一个函数,这个函数有一个参数.这个函数就是我们要进行的信号操作的函数. sa_sigaction,sa_restore和sa_handler差不多的,只是参数不同罢了.这两个元素我们很少使用,就不管了. 
sa_flags用来设置信号操作的各个情况.一般设置为0好了.sa_mask我们已经学习过了 
在使用的时候我们用sa_handler指向我们的一个信号操作函数,就可以了.sa_handler有两个特殊的值:SIG_DEL和SIG_IGN.SIG_DEL是使用缺省的信号操作函数,而SIG_IGN是使用忽略该信号的操作函数. 
linux线程 信号处理相关API介绍
信号产生
int pthread_kill(pthread_t thread, int sig);

向指定ID的线程发送sig信号,如果线程代码内不做处理,则按照信号默认的行为影响

整个进程

成功:0
线程不存在:ESRCH
信号不合法:EINVAL

信号处理

int sigemptyset(sigset_t *set);
int  sigfillset(sigset_t *set);
int sigaddset(sigset_t *set,int signo);
int sigdelset(sigset_t *set,int signo);
int sigismember(sigset_t *set,int signo);

int pthread_sigmask (int how,
const sigset_t *set,
sigset_t *oset)

      用作在主调线程里控制信号掩码。

How:
SIG_BLOCK:     结果集是当前集合参数集的并集
SIG_UNBLOCK:  结果集是当前集合参数集的差集
SIG_SETMASK:  结果集是由参数集指向的集

提示:   除非信号在所有的线程里都阻塞,否则总能将异步信号传输给这个进程。

 

int sigwait(const sigset_t *restrict set, int *restrict signop);


Returns: 0 if OK, error number on failure

sigwait的作用是:挂起进程,对于参数指向的sigset_t里的信号进行监测。如果所监视的信号被阻塞,则它把阻塞信号从挂起信号集中删除,解除对它的阻塞,然后返回。也就是它监测的进程必须是先进行阻塞处理的,它才监测到并且对信号进行解除阻塞。。挂起信号集是系统记录被阻塞的信号的数据结构。
总之:sigwait监测参数指向的sigset_t里的信号一旦有信号属于它且被阻塞,则它解除信号的阻塞,然后返回。

相关实例介绍
#include
#include
#include
#include
#include
#include
#include

void sig_handler(int signum)
{
    static int j = 0;
    static int k = 0;
    pthread_t  sig_ppid = pthread_self();
    // used to show which thread the signal is handled in.
   
    if (signum == SIGUSR1) {
        printf("thread %d, receive SIGUSR1[%d] No. %d\n", sig_ppid,signum, j);
        j++;
    //SIGRTMIN should not be considered constants from userland,
    //there is compile error when use switch case
    } else if (signum == SIGRTMIN) {
        printf("thread %d, receive SIGRTMIN[%d] No. %d\n", sig_ppid,signum, k);
        k++;
    }
}

void* worker_thread()
{

    pthread_t  ppid = pthread_self();
    pthread_detach(ppid);

   
    while (1) {
  //      printf("I'm thread %d, I'm alive\n", ppid);
        sleep(10);
    }
}

void* sigmgr_thread()
{
    sigset_t   waitset, oset;
    siginfo_t  info;
    int        rc;
    pthread_t  ppid = pthread_self();

    pthread_detach(ppid);

    sigemptyset(&waitset);
    sigaddset(&waitset, SIGRTMIN);
    sigaddset(&waitset, SIGUSR1);
#if 1

    while (1)  
    {
        rc = sigwaitinfo(&waitset, &info);
        if (rc != -1)
        {
            printf("sigwaitinfo() fetch the signal - %d\n", rc);
            sig_handler(info.si_signo);
        }
        else
        {
          //  printf("sigwaitinfo() returned err: %d; %m\n", errno);
            printf("sigwaitinfo() returned err: %d; %s\n", errno,strerror(errno));
        }
    }
#endif
  while(1);
}


int main()
{
    sigset_t bset, oset;
    int             i = 0;
    pid_t           pid = getpid();
    pthread_t       ppid[5],mpid;



#if 0
    //block   SIGUSR1
    sigset_t   set;
    sigemptyset(&set);
    sigaddset(&set,   SIGUSR1);
    sigprocmask(SIG_BLOCK,   &set,   NULL);
#endif   
#if 1
    // Block SIGRTMIN and SIGUSR1 which will be handled in
    //dedicated thread sigmgr_thread()
    // Newly created threads will inherit the pthread mask from its creator
    sigemptyset(&bset);
    sigaddset(&bset, SIGRTMIN);
    sigaddset(&bset, SIGUSR1);
    if (pthread_sigmask(SIG_BLOCK, &bset, &oset) != 0)
        printf("!! Set pthread mask failed\n");
   
    // Create the dedicated thread sigmgr_thread() which will handle
    // SIGUSR1 and SIGRTMIN synchronously
#endif
    pthread_create(&mpid, NULL, sigmgr_thread, NULL);
  
    // Create 5 worker threads, which will inherit the thread mask of
    // the creator main thread
    for (i = 0; i < 5; i++) {
        pthread_create(&ppid, NULL, worker_thread, NULL);
    }

    // send out 50 SIGUSR1 and SIGRTMIN signals
    for (i = 0; i < 50; i++) {
  //      kill(pid, SIGUSR1);
          pthread_kill(mpid, SIGUSR1);
  //      printf("main thread, send SIGUSR1 No. %d\n", i);
  //      kill(pid, SIGRTMIN);
          pthread_kill(mpid, SIGRTMIN);
  //      printf("main thread, send SIGRTMIN No. %d\n", i);
        sleep(10);
    }
    exit (0);
}
阅读(788) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~