1.介绍
sigsuspend()
是一个Unix系统调用,它用于临时改变进程的信号屏蔽字并暂停进程执行,直到接收到一个信号。
int sigsuspend(const sigset_t *mask);
其中,mask
参数是一个指向sigset_t
类型的指针,这个sigset_t
类型的变量包含了要设置的新的信号屏蔽字。
sigsuspend()
函数会将进程的当前信号屏蔽字替换为由mask
参数指定的屏蔽字,然后暂停进程执行,直到接收到一个信号。当这个信号处理完毕之后,sigsuspend()
函数返回,并将进程的信号屏蔽字恢复为原来的值。
值得注意的是,sigsuspend()
函数总是返回-1,并设置errno
为EINTR
,因为它总是被一个信号中断。
2.使用场景
sigsuspend()
函数常被用在以下场景:
-
当你需要暂停进程并等待一个信号时。例如,你可能在创建了一个子进程之后,希望等待子进程发送一个表示它已经初始化完成的信号。
-
当你需要临时改变信号屏蔽字,执行一些操作,然后恢复原来的屏蔽字时。例如,你可能想要临时解除对某个信号的阻塞,处理这个信号,然后再重新阻塞这个信号。你可以通过调用
sigsuspend()
函数来实现这个目标,而无需手动保存和恢复信号屏蔽字。
总的来说,sigsuspend()
函数提供了一种简单的方法来暂停进程并等待信号,同时临时改变信号屏蔽字。这使得它在处理复杂的信号处理场景时非常有用。
3.例子
#include <stdio.h> #include <unistd.h> #include <signal.h> #include <sys/wait.h> void handler(int sig) { printf("Received signal %d\n", sig); } int main() { // 创建一个子进程 pid_t pid = fork(); if (pid == 0) { // 子进程 sleep(1); // 让父进程有时间设置信号处理函数和调用sigsuspend() kill(getppid(), SIGUSR1); // 发送信号给父进程 _exit(0); } else if (pid > 0) { // 父进程 struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL); // 设置信号处理函数 sigset_t mask, oldmask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); sigprocmask(SIG_BLOCK, &mask, &oldmask); // 阻塞SIGUSR1 printf("Waiting for signal...\n"); sigsuspend(&oldmask); // 恢复原来的信号屏蔽字并暂停进程 printf("Resuming execution...\n"); sigprocmask(SIG_SETMASK, &oldmask, NULL); // 恢复原来的信号屏蔽字 } else { // fork失败 perror("fork"); return 1; } // 父进程等待子进程结束 if (pid > 0) { wait(NULL); } return 0; }
在这个示例中,父进程首先创建一个子进程,然后设置一个信号处理函数来处理SIGUSR1
信号。父进程接着阻塞SIGUSR1
信号,然后调用sigsuspend()
函数来等待这个信号。子进程则在一秒后发送SIGUSR1
信号给父进程,这将唤醒sigsuspend()
并调用信号处理函数。
1.介绍
sigqueue()
函数用于向进程发送一个信号,并附带额外的数据。与kill()
函数相比,sigqueue()
提供了一种更加强大的信号发送机制,因为它允许你附带一些额外的信息。
#include <signal.h> int sigqueue(pid_t pid, int sig, const union sigval value);
-
pid
是接收信号的进程ID。 -
sig
是要发送的信号。 -
value
是一个sigval
联合体,它可以包含一个整数值(sival_int
)或者一个指针(sival_ptr
)。这个值会被发送到接收信号的进程,并且可以在该进程的信号处理函数中获取。
注意,使用sigqueue()
函数发送信号需要进程有相应的权限。具体来说,发送进程要么是接收进程的所有者,要么具有CAP_KILL
能力。
信号的接收进程可以在信号处理函数中通过siginfo_t
结构体的si_value
成员获取发送过来的值。这个结构体是信号处理函数的第二个参数。
2.例子
void handler(int sig, siginfo_t *info, void *ucontext) { printf("Received signal %d with value %d\n", sig, info->si_value.sival_int); } int main() { struct sigaction act; act.sa_sigaction = handler; act.sa_flags = SA_SIGINFO; sigemptyset(&act.sa_mask); sigaction(SIGUSR1, &act, NULL); union sigval value; value.sival_int = 123; sigqueue(getpid(), SIGUSR1, value); pause(); return 0; }
在这个例子中,主程序发送一个带有额外值的信号给自己,然后在信号处理函数中打印出这个值。这显示了如何使用sigqueue()
函数发送信号,并在信号处理函数中获取额外的值。