Unix高级编程之signal
signal函数相关的细节描述详见另外两篇篇博客,这里不详细赘述:
https://langzi989.github.io/2017/09/08/C++%E5%87%BD%E6%95%B0%E6%8C%87%E9%92%88%E5%AD%A6%E4%B9%A0/
https://langzi989.github.io/2017/05/04/Wait%E5%87%BD%E6%95%B0%E8%AF%A6%E8%A7%A3/
显示信号的描述
信号的个数可以用宏NSIG获取。
显示信号的描述有三种方法:
1 2 3 4 5 6 7 8 9
| #include <string.h> char* strsignal(int sig); void psignal(int sig, char* msg); sys_siglist[sig];
|
上述三种方法的区别
sys_siglist是直接存储信号描述的数组,一般情况下,推荐使用strsignal。
strsignal和psignal函数对locale敏感,会打印出当地的语言。
调用psignal会在本地的错误出输出流输出,msg:strsignalmsg;
如:
1 2
| //此时错误数据流将会打印出:SIGINT:Interrupt psignal(SIGINT, "SIGINT");
|
信号集
许多相关的系统调用涉及到一组不同的信号,这时候需要信号集。linux中使用sigset_t结构体来表示信号集。一般情况,信号集是使用掩码实现的,但是可能有一些是其他实现方式。
信号集结构体相关的函数.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <signal.h> int sigemptyset(sigset_t* set); int sigfillset(sigset_t* set); int sigaddset(sigset_t* set, int sig); int sigdelset(sigset_t* set, int sig); int sigismember(const sigset_t* set, int sig); #define _GNU_SOURCE int sigandset(sigset_t* dest, sigset_t* left, sigset_t* right); int sigorset(sigset_t* dest, sigset_t* left, sigset_t* right); int sigisemptyset(const sigset_t* set);
|
信号掩码(进程中阻塞信号传递)
内核会为每个进程维护一个信号掩码(标识一组信号),当一个信号被传递到该进程的时候,若该信号在信号掩码中,进程会阻塞该信号的传递,直到将该信号从信号掩码中剔除。
向信号掩码中添加一个信号的方式有以下几种:
- 当调用信号处理器程序的时候,可将引发该调用的信号自动添加到信号掩码中,这取决于sigaction函数在安装信号时使用的标志。
- 使用sigaction函数建立信号处理程序时,可以指定一组额外信号,当调用该处理器程序时将阻塞。
- 使用sigprocmask函数修改进程的信号掩码。
sigprocmask函数
1 2
| #include <signal.h> int sigprocmask(int how, const sigset_t* set, sigset_t* old);
|
参数:
- how : 指定修改信号掩码的方式,有三种方式
- SIG_BLOCK : 向指定信号中添加指定信号.
- SIG_UNBLOCK: 将指定信号从原有的信号掩码中移除。若被移除的信号掩码不存在不报错
- SIG_SETMASK: 直接设置(赋值),覆盖原有的值
- set : 需要设置的新的信号掩码集
- old: 旧的信号掩码集。可在设置信号掩码集之后回复原有的信号掩码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <unistd.h> #include <signal.h> int main() { time_t start = time(NULL); sigset_t new_set, pre; sigemptyset(&new_set); sigaddset(&new_set, SIGINT); if (sigprocmask(SIG_SETMASK, &new_set, &pre) == -1) { std::cout<< "sigprocmask set error" << std::endl; } while (true) { sleep(1); time_t end = time(NULL); if (end - start >= 15) { std::cout << "hahah 接触阻塞" << std::endl; sigprocmask(SIG_SETMASK, &pre, NULL); } } }
|
sigpending获取正在等待状态的信号
若进程接收信号被阻塞之后,我们希望获取被阻塞的信号,则可以使用sigpending函数
1 2
| #include <signal.h> int sigpending(sigset_t* set);
|
使用此函数的场景是:若某个进程接收到被阻塞的信号,如果希望这些信号被移出阻塞队列,此时可以通过sigpending获取被阻塞的信号,然后将此信号的处理器函数IGNORE,并将其剔除信号掩码即可。
在信号被阻塞的时候,不对信号做排队处理,即即使进程阻塞了100个SIGINT信号,此时当SIGINT从信号掩码中去除时,该进程接收的还是只是一个SIGINT信号。
sigaction函数
除了signal函数之外,sigaction系统调用是设置信号处理的另一个选择。sigaction和signal函数相比更加灵活和具有可移植性。sigaction允许在不改变信号处理器程序的情况下获取信号的默认处理方式。
Comment and share