sigsuspend、sigqueue

sigsuspend()用于改变进程的信号屏蔽字并暂停执行,直到接收信号。它常用于暂停进程并等待特定信号或临时改变信号屏蔽字。sigqueue()函数则允许发送带有附加数据的信号,提供更灵活的信号通信方式。这两个函数在处理复杂信号管理和进程间通信时非常有用。
摘要由CSDN通过智能技术生成

1.介绍

sigsuspend()是一个Unix系统调用,它用于临时改变进程的信号屏蔽字并暂停进程执行,直到接收到一个信号。

int sigsuspend(const sigset_t *mask);

其中,mask参数是一个指向sigset_t类型的指针,这个sigset_t类型的变量包含了要设置的新的信号屏蔽字。

sigsuspend()函数会将进程的当前信号屏蔽字替换为由mask参数指定的屏蔽字,然后暂停进程执行,直到接收到一个信号。当这个信号处理完毕之后,sigsuspend()函数返回,并将进程的信号屏蔽字恢复为原来的值。

值得注意的是,sigsuspend()函数总是返回-1,并设置errnoEINTR,因为它总是被一个信号中断。

2.使用场景

sigsuspend()函数常被用在以下场景:

  1. 当你需要暂停进程并等待一个信号时。例如,你可能在创建了一个子进程之后,希望等待子进程发送一个表示它已经初始化完成的信号。

  2. 当你需要临时改变信号屏蔽字,执行一些操作,然后恢复原来的屏蔽字时。例如,你可能想要临时解除对某个信号的阻塞,处理这个信号,然后再重新阻塞这个信号。你可以通过调用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()函数发送信号,并在信号处理函数中获取额外的值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值