1.介绍
sigprocmask
是UNIX或Linux系统编程中一个重要的系统调用,它可以用来改变进程的信号掩码。
#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
-
how
:决定如何修改当前信号掩码。有三种可能的值:-
SIG_BLOCK
:将set中的信号添加到当前的信号掩码中,这样就会阻塞set中的信号。 -
SIG_UNBLOCK
:将set中的信号从当前的信号掩码中删除,这样就不会阻塞set中的信号。 -
SIG_SETMASK
:将当前的信号掩码设置为set指向的值。
-
-
set
:指向一个信号集,这个信号集用来改变当前的信号掩码。 -
oldset
:如果不是NULL,则在修改信号掩码之前,旧的信号掩码将被保存在这里。
这个函数的返回值是0,如果成功,-1如果失败。如果失败,errno将被设置为相应的错误。
2.例子
#include <stdio.h> #include <signal.h> #include <unistd.h> int main() { sigset_t newmask, oldmask, pending; // 初始化一个包含 SIGINT 的新信号集 sigemptyset(&newmask); sigaddset(&newmask, SIGINT); // 将当前信号掩码设置为新信号集,保存旧的信号掩码 if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) { perror("sigprocmask"); return 1; } // 在一段时间内阻塞 SIGINT printf("SIGINT is now blocked for 5 seconds.\n"); sleep(5); // 检查是否有挂起的 SIGINT if (sigpending(&pending) < 0) { perror("sigpending"); return 1; } if (sigismember(&pending, SIGINT)) { printf("SIGINT is pending.\n"); } // 将信号掩码恢复到原始状态 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) { perror("sigprocmask"); return 1; } printf("SIGINT is no longer blocked.\n"); return 0; }
在这个例子中,我们首先创建了一个新的信号集 newmask
,并将 SIGINT
添加到这个集合中。然后我们调用 sigprocmask
,将当前的信号掩码设置为 newmask
,并将旧的信号掩码保存在 oldmask
中。接着我们让进程休眠5秒,期间 SIGINT
信号是阻塞的。在休眠结束后,我们检查是否有挂起的 SIGINT
信号,然后再次调用 sigprocmask
,将信号掩码恢复到原始状态。
注意,如果在信号被阻塞的期间,这个信号发生了,那么这个信号就是挂起的。当信号再次被解阻塞时,这个信号就会被立即传递给进程。在该函数返回之前,至少要将其中之一递送给该进程。
3.信号集sigset_t的含义
sigset_t
数据结构表示的是一个信号集合,每一位对应一个信号。当某位被设置为1时,表示对应的信号被加入到这个集合中;当某位被设置为0时,表示对应的信号被从这个集合中删除。但这个信号集合是怎么被使用的,取决于你使用它的上下文。
在sigprocmask
的上下文中,sigset_t
中的1代表阻塞对应的信号,0代表不阻塞对应的信号。所以,对于sigprocmask
函数,sigset_t
的解释应该是这样的:
-
如果你使用
SIG_BLOCK
,那么sigprocmask
将把set
参数指向的信号集中的所有信号添加到进程的信号掩码中。这就意味着,所有在set
中设置为1的信号将被阻塞。 -
如果你使用
SIG_UNBLOCK
,那么sigprocmask
将把set
参数指向的信号集中的所有信号从进程的信号掩码中删除。这就意味着,所有在set
中设置为1的信号将被解阻塞。 -
如果你使用
SIG_SETMASK
,那么sigprocmask
将把进程的信号掩码设置为set
参数指向的信号集。这就意味着,所有在set
中设置为1的信号将被阻塞,而所有在set
中设置为0的信号将被解阻塞。信号集仅仅是个集合,1不一定代表屏蔽也不一定代表不屏蔽。
七、sigpending
1.介绍
sigpending()
用于获取当前进程或线程的未决信号集。
#include <signal.h> int sigpending(sigset_t *set);
该函数接受一个 sigset_t
类型的指针作为参数,这个指针指向一个信号集。当函数返回时,这个信号集中的位被设置为当前进程的未决信号。
sigpending()
返回 0 表示成功,-1 表示失败。如果失败,错误代码会被设置在 errno
中。
2.例子
#include <stdio.h> #include <signal.h> #include <unistd.h> void handler(int sig) { printf("Received signal %d\n", sig); } int main() { signal(SIGUSR1, handler); sigset_t sig; sigemptyset(&sig); sigaddset(&sig,SIGUSR1); sigprocmask(SIG_BLOCK, &sig, NULL); printf("Sending signal %d\n", SIGUSR1); raise(SIGUSR1); if (sigpending(&sig) == 0) { if (sigismember(&sig, SIGUSR1)) { printf("Signal %d is pending\n", SIGUSR1); } else { printf("Signal %d is not pending\n", SIGUSR1); } } else { printf("sigpending failed\n"); } return 0; }