Linux C编程--进程间通信(IPC)3--信号集和发送信号介绍
Linux信号集
1.信号集概念
信号集是一个能表示多个信号的数据类型,sigset_t set ;set即一个信号集。
既然是一个集合,就需要对集合进行添加/删除等操作。
int sigemptyset(sigset_t *set); 将set集合置空
int sigfillset(sigset_t *set); 将所有信号加入set集合
int sigaddset(sigset_t *set,int signo); 将signo信号加入到set集合
int sigdelset(sigset_t *set,int signo); 从set集合中移除signo信号
int sigismember(const sigset_t *set,int signo); signo判断信号是否存在于set集合中
2.信号集的操作
1>sigprocmask(查询或设置信号掩码)
相关函数
signal,sigaction,sigpending,sigsuspend
表头文件
#include<signal.h>
定义函数
int sigprocmask(int how,const sigset_t *set,sigset_t * oldset);
函数说明
sigprocmask()可以用来改变目前的信号遮罩,其操作依参数how来决定
SIG_BLOCK 新的信号遮罩由目前的信号遮罩和参数set 指定的信号遮罩作联集
SIG_UNBLOCK 将目前的信号遮罩删除掉参数set指定的信号遮罩
SIG_SETMASK 将目前的信号遮罩设成参数set指定的信号遮罩。
如果参数oldset不是NULL指针,那么目前的信号遮罩会由此指针返回。
返回值
执行成功则返回0,如果有错误则返回-1。
错误代码
EFAULT 参数set,oldset指针地址无法存取。
EINTR 此调用被中断
注:如果将set设为一空指针,那么进程的信号掩码将不会改变,这时how的位也是没有以意义的。
下面给出一个例子,用来说明这个函数
功能是打印调用进程的信号掩码中的信号的名称
#include <signal.h>#include <stdio.h>int quitflag=0;int main(){void sig_int(int);sigset_t newmask, oldmask, zeromask;if(signal(SIGINT,&sig_int)==-1){printf("Couldn't register signal hanlder for SIGINT!\n");exit(1);}if(signal(SIGQUIT,&sig_int)==-1){printf("Couldn't register signal hanlder for SIGQUIT!\n");exit(2);}sigemptyset(&zeromask);sigemptyset(&newmask);sigaddset(&newmask,SIGQUIT);if(sigprocmask(SIG_BLOCK, &newmask, &oldmask)<0){printf("SIG_BLOCK error.\n");exit(3);}while(quitflag==0)sigsuspend(&zeromask);printf("process wake up.\n");quitflag=0;if(sigprocmask(SIG_SETMASK,&oldmask,NULL)<0)exit(0);}void sig_int(int signum){if(signum==SIGINT)printf("\n interrupt \n");else if (signum==SIGQUIT){printf("catch SIGQUIT \n");quitflag=1;}return ;}1. 函数说明:
kill和raise是用来发送信号的:
kill把信号发送给进程或进程组;
raise把信号发送给(进程)自身.
他们的原型如下:
#include
int kill(pid_t pid, int signo);
int raise(int signo);
成功则返回0, 出错则返回-1
从原型上可以看出, raise函数是可以通过kill实现的.
raise(signo);
等价于:
kill(getpid(), signo);
2. pid参数:
kill函数中的pid参数, 它有以下4种情况:
pid > 0: 将该信号发送给进程ID为pid的进程.
pid == 0: 将该信号发送给与发送进程属于同一进程组的所有进程(不包括内核进程和init进程). 此时, 发送进程必须具有向这些进程发送信号的权限.
pid < 0: 将该信号发给其进程组ID等于pid绝对值的所有进程(不包括内核进程和init进程). 此时, 发送进程必须具有向这些进程发送信号的权限.
pid == -1: 将该信号发送给发送进程有权限向它们发送信号的系统上的所有进程.(不包括内核进程和init进程).
3. signo参数:
POSIX.1将编号为0的信号定义为空信号. 如果signo参数是0, 则kill仍执行正常的错误检查, 但不发送信号. 这被用来确定一个进程是否存在.
下面给出两个例子说明这两个函数的使用方法:
1.raise函数的使用
#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>int usr_interrupt=0;void synch_signal(int signum){usr_interrupt=1;}void child_function(){printf(" I'm child process. My pid is %d \n",getpid());sleep(5);kill(getppid(),SIGUSR1);puts("Good bye! \n");exit(0);}int main(){struct sigaction usr_action;sigset_t block_mask;pid_t child_id;sigfillset(&block_mask);usr_action.sa_handler=synch_signal;usr_action.sa_mask=block_mask;usr_action.sa_flags=0;sigaction(SIGUSR1, &usr_action,NULL);child_id=fork();if(child_id==0)child_function();while(!usr_interrupt);puts("That's all!");return 0;}