信号处理

信号集合


SIGINT	 2	Term	Interrupt from keyboard
SIGQUIT	 3	Core	Quit from keyboard
SIGILL	 4	Core	Illegal Instruction
SIGABRT	 6	Core	Abort signal from abort(3)
SIGFPE	 8	Core	Floating point exception
SIGKILL	 9	Term	Kill signal
SIGSEGV	11	Core	Invalid memory reference
SIGPIPE	13	Term	Broken pipe: write to pipe with no readers
SIGALRM	14	Term	Timer signal from alarm(2)
SIGTERM	15	Term	Termination signal
SIGUSR1	30,10,16	Term	User-defined signal 1
SIGUSR2	31,12,17	Term	User-defined signal 2
SIGCHLD	20,17,18	Ign	Child stopped or terminated
SIGCONT	19,18,25	Cont	Continue if stopped
SIGSTOP	17,19,23	Stop	Stop process
SIGTSTP	18,20,24	Stop	Stop typed at tty
SIGTTIN	21,21,26	Stop	tty input for background process
SIGTTOU	22,22,27	Stop	tty output for background process

信号处理

  • struct sigaction结构体和函数
struct sigaction
{
    void (*sa_handler)(int);	   //老类型的信号处理函数指针
    void (*sa_sigaction)(int, siginfo_t *, void *);//新类型的信号处理函数指针
    sigset_t sa_mask;			   //将要被阻塞的信号集合
    int sa_flags;				   //信号处理方式掩码 (  SA_SIGINFO )
    void (*sa_restorer)(void);	   //保留,不要使用
};
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
  • 各字段以及函数说明
    • 字段sa_handler是一个函数指针,用于指向原型为void handler(int)的信号处理函数地址, 即老类型 的信号处理函数(如果用这个再将sa_flags = 0,就等同于signal()函数)
    • 字段sa_sigaction也是一个函数指针,用于指向原型为:
      void handler(int iSignNum, siginfo_t *pSignInfo, void *pReserved);
      的信号处理函数,即新类型的信号处理函数
      该函数的三个参数含义为:
      iSignNum:传入的信号
      pSignInfo:与该信号相关的一些信息,它是个结构体
      pReserved:保留,现没用,通常为NULL
    • 字段sa_handler和sa_sigaction只应该有一个生效,如果想采用老的信号处理机制,就应该让sa_handler指向正确的信号处理函数,并且让字段sa_flags为0;否则应该让sa_sigaction指向正确的信号处理函数,并且让字段sa_flags包含SA_SIGINFO选项
    • 字段sa_mask是一个包含信号集合的结构体,该结构体内的信号表示在进行信号处理时,将要被阻塞的信号。针对sigset_t结构体,有一组专门的函数对它进行处理,
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
int sigemptyset(sigset_t *set);					//清空信号集合set
int sigfillset(sigset_t *set);					//将所有信号填充进set中
int sigaddset(sigset_t *set, int signum);			//往set中添加信号signum
int sigdelset(sigset_t *set, int signum);			//从set中移除信号signum
int sigismember(const sigset_t *set, int signum);	//判断signum是否包含在set中(是:返回1,否:0)
int sigpending(sigset_t *set);					//将被阻塞的信号集合由参数set指针返回
  • 用sigaction实现和signal(只能传递一个参数)一样的功能。
#include<signal.h>
#include<stdio.h>
void handle(int signo)
{
printf("signo: %d\n",signo);
}
main()
{
  	struct sigaction st;
  	st.sa_handler = handle;
  	st.sa_flags = 0;
  	sigaction(SIGINT,&st,NULL);
  	while(1)
  	{
   		sleep(1);
  	}
}
  • 用sigaction实现调用新的信号处理函数
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>

int g_iSeq = 0;

void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
{
    int iSeq = g_iSeq++;
    printf("%d Enter SignHandlerNew,signo:%d.\n",iSeq,iSignNo);
    sleep(3);
    printf("%d Leave SignHandlerNew,signo:%d\n",iSeq,iSignNo);
}
int main()
{
    char szBuf[8] = {0};
    int iRet = 0;
    struct sigaction act;
    act.sa_sigaction = SignHandlerNew;
    act.sa_flags = SA_SIGINFO | SA_RESTART;
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, SIGQUIT);
    sigaction(SIGINT,&act,NULL);
    do{
        iRet = read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
        if(iRet < 0){
            perror("read fail");
            break;
        }
        szBuf[iRet] = 0;
        printf("Get: %s",szBuf);
    }while(strcmp(szBuf,"quit\n") != 0);
    return 0;
}

当一个信号被阻塞之后,在解除阻塞之前,该信号发生了多次,但是解除阻塞的时候,内核只会向进程发送一个信号而已,而不管在其阻塞期间有多少个信号产生,因为linux并不会对信号进行排队。另外,这里用到了打断read输入的中断处理,必须要加参数SA_RESTART,对于signal函数而言,它安装的信号处理函数,系统默认会自动重启被中断的系统调用,而不是让它出错返回。而对于sigaction函数而言,必须要自己指定SA_RESTART实现重启功能,如果不指定则会read失败,提示read的时候中断发生。

sigprocmask信号阻塞

  • 函数原型
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
  • 函数说明
    参数how的值为如下3者之一:
    a:SIG_BLOCK ,将参数2的信号集合添加到进程原有的阻塞信号集合中
    b:SIG_UNBLOCK ,从进程原有的阻塞信号集合移除参数2中包含的信号
    c:SIG_SETMASK,重新设置进程的阻塞信号集为参数2的信号集
    参数set为阻塞信号集
    参数oldset是传出参数,存放进程原有的信号集,通常为NULL

  • 添加全程阻塞代码案例:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iSeq=0;
void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
{
    int iSeq=g_iSeq++;
    printf("%d Enter SignHandlerNew,signo:%d\n",iSeq,iSignNo);
    sleep(3);
    printf("%d Leave SignHandlerNew,signo:%d\n",iSeq,iSignNo);
}
int main()
{
    char szBuf[8];
    int iRet;
    //屏蔽掉SIGQUIT信号
    sigset_t sigSet;
    sigemptyset(&sigSet);
    sigaddset(&sigSet,SIGQUIT);
    sigprocmask(SIG_BLOCK,&sigSet,NULL);
    struct sigaction act;
    act.sa_sigaction=SignHandlerNew;
    act.sa_flags=SA_SIGINFO;
    sigemptyset(&act.sa_mask);
    sigaction(SIGINT,&act,NULL);
    while(1);
    return 0;
}
  • 取消阻塞代码案例:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
int g_iSeq=0;
void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
{
    int iSeq=g_iSeq++;
    printf("%d Enter SignHandlerNew,signo:%d\n",iSeq,iSignNo);
    sleep(3);
    printf("%d Leave SignHandlerNew,signo:%d\n",iSeq,iSignNo);
}
int main()
{
    //屏蔽掉SIGINT和SIGQUIT信号,SigHandlerNew将不能再捕捉SIGINT和SIGQUIT
    sigset_t sigSet;
    sigemptyset(&sigSet);
    sigaddset(&sigSet,SIGINT);
    sigaddset(&sigSet,SIGQUIT);
    sigprocmask(SIG_BLOCK,&sigSet,NULL);//将SIGINT、SIGQUIT屏蔽
    struct sigaction act;
    act.sa_sigaction=SignHandlerNew;
    act.sa_flags=SA_SIGINFO;
    sigemptyset(&act.sa_mask);
    sigaction(SIGINT,&act,NULL);
    sigaction(SIGQUIT,&act,NULL);
    int iCount = 0;
    while(1)
    {
        if(iCount > 3)
        {
            sigset_t sigSet2;
            sigemptyset(&sigSet2);
            sigaddset(&sigSet2, SIGINT);
            sigprocmask(SIG_UNBLOCK, &sigSet2, NULL);
        }
        iCount ++;
        sleep(2);
    }
    return 0;
}
  • 测试信号
#include <signal.h>
#include <unistd.h>
void handler(int signum, siginfo_t* pInfo, void* pReversed)
{
    printf("receive signal %d \n",signum);
}
int main()
{
    sigset_t new_mask, old_mask, pending_mask;
    sigemptyset(&new_mask);
    sigaddset(&new_mask, SIGINT);
    if(sigprocmask(SIG_BLOCK, &new_mask, &old_mask))
        printf("block signal SIGINT error\n");
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = handler;
    if(sigaction(SIGINT, &act, NULL))
        printf("install signal SIGINT error\n");
    sleep(10);
    printf("now begin to get pending mask and unblock SIGINT\n");
    if(sigpending(&pending_mask) < 0)//将阻塞信号全部添加到pending_mask信号集中并返回
        printf("get pending mask error\n");
    if(sigismember(&pending_mask, SIGINT))
        printf("signal SIGINT is pending\n");
    if(sigprocmask(SIG_SETMASK, &old_mask, NULL) < 0)
        printf("unblock signal error\n");
    printf("signal unblocked\n");
    sleep(10);
    return 0;
}
  • 信号的总结
    • 信号本质
      信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
    • 信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。
posted @ 2015-04-24 17:07  王道鹰击长空  阅读(98)  评论(0编辑  收藏  举报