信号-sigset_t,sigaction

信号

一、 sigset_t

sigset_t 是一个数据类型,用于表示信号集。信号集本质上是一个信号的集合,用来指定多个信号。例如,您可以使用一个 sigset_t 变量来存储一组信号,然后使用该集合在诸如信号阻塞、信号等待等操作中。

1.1 使用方法

  1. 初始化信号集

    在使用信号集之前,需要将其初始化为一个空集或包含所有信号的集合。这可以通过 sigemptysetsigfillset 函数来完成。

    sigset_t set;  
    sigemptyset(&set); // 初始化为空集  
    sigfillset(&set); // 初始化为包含所有信号的集合
    
  2. 添加或者删除信号

    使用 sigaddsetsigdelset 函数可以向信号集中添加或删除特定的信号。

    sigaddset(&set, SIGINT); // 添加 SIGINT 信号到 set  
    sigdelset(&set, SIGQUIT); // 从 set 中删除 SIGQUIT 信号
    sigismember(&set, SIGINT);// 判断set中是否包含指定信号
    
  3. 修改进程的信号屏蔽字

    sigprocmaskUnixLinux系统中用于修改当前进程的信号屏蔽字(signal mask)的函数。信号屏蔽字是一个位掩码,它决定了哪些信号应当被当前进程阻塞,即不会被递送到进程进行处理。

    #include <signal.h>  
    int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    
    1. 参数:

      1. how:指定了如何修改当前进程的信号屏蔽字。它可以取以下三个值之一:
        • SIG_BLOCK:将set所指向的信号集中所包含的信号加到当前的信号屏蔽字中。
        • SIG_UNBLOCK:将set所指向的信号集中的信号从当前的信号屏蔽字中移除。
        • SIG_SETMASK:将当前进程的信号屏蔽字设置为set所指向的信号集中所包含的信号。
      2. set:一个指向sigset_t类型的指针,表示要修改或检测的信号集。如果该值为NULL,则忽略该参数并不会改变当前进程的信号屏蔽集。
      3. oldset:一个指向sigset_t类型的指针,用于接收调用sigprocmask之前的信号屏蔽字。如果此参数不为NULL,则调用后将保存旧的信号屏蔽字到oldset中。
    2. 返回值:

      如果成功,则返回0;否则返回-1,并设置全局变量errno以指示错误。

  4. 示例:

    #include <stdio.h>  
    #include <signal.h>  
    #include <stdlib.h>  
    
    void sig_handler(int signo) {  
        printf("Received signal %d\n", signo);  
        exit(0);  
    }  
    
    int main() {  
        sigset_t blockset, oldset;  
    
        // 初始化blockset为空集  
        sigemptyset(&blockset);  
        // 将SIGINT信号添加到blockset中  
        sigaddset(&blockset, SIGINT);  
    
        // 绑定SIGINT信号的处理器  
        if (signal(SIGINT, sig_handler) == SIG_ERR) {  
            perror("signal(SIGINT) error");  
            exit(1);  
        }  
    
        // 阻塞SIGINT信号  
        if (sigprocmask(SIG_BLOCK, &blockset, &oldset) < 0) {  
            perror("sigprocmask(SIG_BLOCK) error");  
            exit(1);  
        }  
    
        // 在这里执行一些操作,SIGINT信号将被阻塞  
    
        // 恢复原来的信号屏蔽字  
        if (sigprocmask(SIG_SETMASK, &oldset, NULL) < 0) {  
            perror("sigprocmask(SIG_SETMASK) error");  
            exit(1);  
        }  
    
        // 从这里开始,SIGINT信号将不再被阻塞  
    
        return 0;  
    }
    

二、struct sigaction

2.1 结构介绍

struct sigaction 是一个结构体,用于指定当特定信号到达时应该如何处理它。这个结构体允许用户定义一个信号处理函数,以及在调用信号处理函数期间需要阻塞的信号集。它提供了比传统的 signal() 函数更多的控制和灵活性。

struct sigaction {
    void     (*sa_handler)(int);
    void     (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int      sa_flags;
    void     (*sa_restorer)(void);
};

struct sigaction 结构体通常包括以下几个字段:

  1. void (*sa_handler)(int)
    • 这是指向信号处理函数的指针。该函数的类型为 void handler(int signum),其中 signum 是被捕获信号的编号。
    • 可以设置为 SIG_IGN 忽略信号,或 SIG_DFL 使用默认的信号处理方式。
  2. sa_sigaction
    • 这是另一种信号处理函数的指针,类型为 void handler(int signum, siginfo_t *info, void *context)
    • sa_handler 不同,sa_sigaction 提供了更多的信息,例如信号的额外数据(通过 siginfo_t 结构),以及程序的上下文(通过 ucontext_t,通常作为 void * 参数传递)。
    • 如果设置了 SA_SIGINFO 标志,则应使用 sa_sigaction 代替 sa_handler
  3. sa_mask:
    • 类型为 sigset_t,用于指定在当前信号处理函数执行期间需要阻塞的其他信号。
    • 例如,如果你不希望在处理一个信号时被另一个信号中断,则可以将那个信号加入到 sa_mask 中。
  4. sa_flags:
    • SA_RESTART:使被信号中断的系统调用自动重新启动。
    • SA_NOCLDSTOP:如果设置了,子进程停止时不会通知父进程。
    • SA_NOCLDWAIT:使父进程不等待子进程退出,防止僵尸进程。
    • SA_SIGINFO:允许使用 sa_sigaction 字段而非 sa_handler。
  5. sa_restorer:不再使用。通常为NULL

2.2 方法介绍

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

参数:

  • signum:信号编号
  • act:指向struct sigaction结构的指针,该结构指定了新的信号处理设置
  • oldact:可选参数。如果不为NULL,则存储信号的前一个处理设置。

2.3 实例

#include <stdio.h>
#include <signal.h>
#include <string.h>

void handle_sigint(int sig, siginfo_t *info, void *context) {
    printf("Received SIGINT (signal number %d).\n", sig);
    printf("Signal originates from process %ld.\n", (long)info->si_pid);
}

int main() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_sigaction = handle_sigint;
    sa.sa_flags = SA_SIGINFO;

    sigaction(SIGINT, &sa, NULL);

    printf("Waiting for SIGINT (Ctrl+C)...\n");
    while (1) {
        sleep(1);
    }

    return 0;
}

三、signal()

signal() 允许程序指定一个信号处理函数,当特定信号到达时,该函数会被调用。其基本用法和功能比较简单,但在现代操作系统中,通常推荐使用更灵活且功能更强大的 sigaction() 代替。

不推荐使用。推荐使用sigaction()。

3.1 方法介绍

#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int);

参数:

  • signum:要处理的信号编号
  • handler:指向函数的指针,该函数将作为信号处理程序使用。这个参数还可以是特殊值 SIG_IGN(忽略信号)或 SIG_DFL(恢复信号的默认处理)。

3.2 实例

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

// 信号处理函数
void signal_handler(int signum) {
    printf("Caught signal %d, but we're not exiting...\n", signum);
}

int main() {
    // 设置 SIGINT 的处理函数为 signal_handler
    if (signal(SIGINT, signal_handler) == SIG_ERR) {
        printf("Error: Unable to set signal handler.\n");
        return 1;
    }

    // 循环,等待信号的到来
    while(1) {
        printf("Sleeping for 1 second...\n");
        sleep(1);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值