信号阻塞
本节介绍信息阻塞的使用方法。
#include <signal.h>
int sigsuspend(const sigset_t *sigsetMask);
int pause(void);
函数 sigsuspend 原型分析:
- 此函数返回 -1。
- 参数 sigsetMask 是指定的信号掩码。
函数 pause 原型分析:
- 此函数返回 -1。
sigsuspend 函数将进程的当前信号屏蔽字设置为由 sigsetMask 指定的值,并且使得当前进程挂起,当 sigsetMask 中指定的某个信号到来后,因为屏蔽而不被处理,同时也不会影响进程的挂起状态,而 sigsetMask 之外的信号发生时,信号将执行并且从信号处理函数返回后,解除进程挂起状态并且 sigsuspend 函数将进程的信号屏蔽字设置为之前的值,返回值是 -1 并设置 errno 为 EINTR。
pause 函数将使调用进程挂起直到捕捉到任何一个信号,只有执行了一个信号处理函数并从其返回,pause 函数才返回,返回值是 -1 并设置 errno 为 EINTR。
修改信号屏蔽字可以屏蔽或解除屏蔽所选择的信号,使用这种技术可以保护不希望由信号中断的代码临界区,下面是一种保护临界区代码的方法。
……
sigprocmask(SIG_BLOCK, &newmask, &oldmask);
…… /* 临界区代码 */
sigprocmask(SIG_SETMASK, &oldmask, NULL);
pause();
……
上面程序片段,使用 sigprocmask 函数屏蔽选择的信号,当临界区代码执行完毕后再解除被屏蔽的信号,然后调用 pause 函数等待屏蔽的信号递送。这个过程看似对临界区进行了很好的保护,但这里有一个很严重的问题,如果在 sigprocmask 函数解除屏蔽时刻和 pause 函数之间发生了信号,则 pause 函数可能会永远阻塞,也就是说在这个时间段,信号将会丢失。sigsuspend 函数可看成是这个过程的一个原子操作,因此调用 sigsuspend 函数将不会出现这样一个时间段。
以下函数将同步等待未决信号,同时解除屏蔽状态。如果有多个信号,则以串行的方式从小到大返回。
#include <signal.h>
int sigwait(const sigset_t *sigset, int *piSig);
int sigwaitinfo(const sigset_t *sigset, struct siginfo *psiginfo);
函数 sigwait 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号。
- 参数 sigset 是指定的信号集。
- 输出参数 piSig 返回未决的信号。
函数 sigtimedwait 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号。
- 参数 sigset 是指定的信号集。
- 输出参数 psiginfo 返回未决的信号信息。
- 参数 ptv 是等超时值。
sigwait 函数使调用进程或者线程挂起,直到 sigset 中包含的信号未决,并将未决的信号通过 piSig 返回,此信号将从屏蔽字中删除,注意,sigset 中的信号是被屏蔽的。
sigwaitinfo 函数使调用进程或者线程挂起,直到 sigset 中包含的信号未决,并将未决的信号通过 psiginfo 返回,与 sigwait 函数不同的是,sigwaitinfo 函数以 siginfo_t类型返回信号信息,意味着将返回更多的信号信息。
如果没有未决的信号,则 sigwait 函数和 sigwaitinfo 函数将永远阻塞,有些时候,这种情况是程序所不允许的,调用 sigtimedwait 函数可以设置一个等待时间,其他功能同 sigwaitinfo 函数一样。需要注意的是,如果 ptv 为 NULL,则永远等待,直到产生未决的信号。
以下函数为信号等待提供了超时机制,当指定的时间超时时函数返回并设置 errno 为 EAGAIN。特殊地,如果参数 ptv 为 NULL,则永远等待直到信号未决。
#include <signal.h>
int sigtimedwait(const sigset_t *sigset,
struct siginfo *psiginfo,
const struct timespec *ptv);
函数 sigtimedwait 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号。
- 参数 sigset 是指定的信号集。
- 输出参数 psiginfo 返回未决的信号信息。
- 参数 ptv 是等待时间信息。
下面程序展示了 sigwait 函数的使用方法。
#include <stdio.h>
#include <signal.h>
int main (int argc, char *argv[])
{
sigset_t newmask;
int sig;
int ret;
sigemptyset(&newmask);
sigaddset(&newmask, SIGALRM);
sigprocmask(SIG_BLOCK, &newmask, NULL);
alarm(1);
ret = sigwait(&newmask, &sig);
if (!ret) {
if (sig == SIGALRM) {
fprintf(stdout, "Signal SIGALRM.\n");
}
}
return (0);
}
在 SylixOS Shell 下运行这段程序,从程序结果可以看出 sigwait 函数通过 sig 将被屏蔽的 SIGALRM 信号返回。
#./Sigwait_Usage
Signal SIGALRM.