Linux信号实践(4) --可靠信号

简介: Sigaction#include int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);功能:   sigaction函数用于改变进程接收到特定信号后的行为。

Sigaction

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

功能:

   sigaction函数用于改变进程接收到特定信号后的行为。

参数

   第一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)

   第二个参数是指向结构sigaction的指针,在结构 sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理

   第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。

返回值:函数成功返回0,失败返回-1

 

sigaction结构体

  第二个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等

struct sigaction {
//信号处理程序 不接受额外数据(比较过时)
	void (*sa_handler)(int);

//信号处理程序能接受额外数据,和sigqueue配合使用(支持信号排队,信号传送其他信息),推荐使用
	void (*sa_sigaction)(int, siginfo_t *, void *); 		

sigset_t sa_mask; 	//屏蔽
	int sa_flags; 		//表示信号的行为:SA_SIGINFO表示能接受数据
	void (*sa_restorer)(void); //废弃不用了
};
//简单示例1: 用sigaction简单替换signal函数
void signalAction(int signo, siginfo_t *signalInfo, void *p)
{
    cout << "signal = " << signo << ", desc: " << strsignal(signo) << endl;
}

int main()
{
    struct sigaction act;
    //注意:回调函数句柄sa_handler、sa_sigaction只能选其一!!!
    //act.sa_handler = sigHandler;
    act.sa_sigaction = signalAction;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;
    if (sigaction(SIGINT,&act,NULL) == -1)
        err_exit("sigaction error");

    pause();
}
//简单实例2: 用sigaction模拟signal函数
sighandler_t mySignal(int signum, sighandler_t handler)
{
    struct sigaction act;
    struct sigaction oldAct;
    act.sa_handler = handler;
    sigemptyset(&act.sa_mask);
    act.sa_flags = 0;

    if (sigaction(signum, &act, &oldAct) == -1)
        return SIG_ERR;
    return oldAct.sa_handler;
}

sa_mask选项

    sa_mask specifies a mask of signals which should be blocked/** 指定一个信号集的掩码, 在这个掩码中的信号将要阻塞**/      (i.e., added  to  the  signal mask of the thread in which the signal handler is invoked) 

during execution of the signal handler.  In addition, the signal which triggered the handler will be blocked, 

unless the SA_NODEFER flag is used.

  /** 在执行handler 的时候, 如果此时进程收到了sa_mask所包含的信号, 则这些信号将不会被响应, 直到handler函数执行完毕

与sigprocmask不同是: sigprocmask 是指定该进程的信号屏蔽字-> 屏蔽该信号, 不会接收该信号, 而sa_mask则是接收了该信号, 但是不会相应该信号**/

//示例: 将sa_mask选项设置以后的效果
/** 在进程相应SIGINT信号时, 如果此时有SIGQUIT信号抵达, SIGQUIT信号也不会被响应, 直到SIGINT信号相应完成之后, 才会去相应SIGQUIT信号(如运行截图所示)**/
int main()
{
    struct sigaction act;
    act.sa_handler = sigHandler;
    sigemptyset(&act.sa_mask);
    // 添加下面一行后: 在响应SIGINT信号时, 是不会被中断的
    sigaddset(&act.sa_mask, SIGQUIT);
    act.sa_flags = 0;
    if (sigaction(SIGINT, &act, NULL) == -1)
        err_exit("sigaction error");

    while (true)
        pause();
}
void sigHandler(int signo)
{
    cout << "catch a signal, signo = " << signo << ", desc: " << strsignal(signo) << endl;
    sleep(10);
}

//运行截图

 

 

sa_flags: 详细信息

 

siginfo_t结构:

siginfo_t{
    int      si_signo;    /* Signal number */
    int      si_errno;    /* An errno value */
    int      si_code;     /* Signal code */
    int      si_trapno;   /* Trap number that caused
                                        hardware-generated signal
                                        (unused on most architectures) */
    pid_t    si_pid;      /* Sending process ID */
    uid_t    si_uid;      /* Real user ID of sending process */
    int      si_status;   /* Exit value or signal */
    clock_t  si_utime;    /* User time consumed */
    clock_t  si_stime;    /* System time consumed */
    sigval_t si_value;    /* Signal value */
    int      si_int;      /* POSIX.1b signal */
    void    *si_ptr;      /* POSIX.1b signal */
    int      si_overrun;  /* Timer overrun count; POSIX.1b timers */
    int      si_timerid;  /* Timer ID; POSIX.1b timers */
    void    *si_addr;     /* Memory location which caused fault */
    long     si_band;     /* Band event (was int in
                                        glibc 2.3.2 and earlier) */
    int      si_fd;       /* File descriptor */
    short    si_addr_lsb; /* Least significant bit of address
                                        (since Linux 2.6.32) */
}

sigqueue

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);

功能

   sigqueue是新的发送信号系统调用,主要是针对实时信号提出的支持信号带有参数,与函数sigaction()配合使用

   和kill函数相比多了一个参数:const union sigval value(int kill(pid_t pid, int sig)),因此sigqueue()可以比kill()传递更多的信息,但sigqueue()只能向一个进程发送信号,而不能发送信号给一个进程组。

参数

   参数1是指定接收信号的进程id,参数2确定即将发送的信号;

   参数3是一个联合数据结构union sigval,指定了信号传递的参数,即通常所说的4字节值。


sigval联合体

typedef union sigval{
    int sival_int;
    void *sival_ptr;
} sigval_t;
//综合实验sigaction+sigqueue
void onSa_SignalAction(int signalNum, siginfo_t *signalInfo, void *p)
{
    cout << "signalNum = " << signalNum << endl;
    //int recValue = signalInfo -> si_value.sival_int;  同下
    int recValue = signalInfo -> si_int;
    cout << "recvValue = " << recValue << endl;
}

int main()
{
    struct sigaction act;

    sigemptyset(&act.sa_mask);
    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = onSa_SignalAction;
    if (sigaction(SIGINT,&act,NULL) == -1)
        err_exit("sigaction error");

    pid_t pid = fork();
    if (pid == -1)
        err_exit("fork error");
    else if (pid == 0)  //In Child
    {
        /*
        typedef union sigval{
            int sival_int;
            void *sival_ptr;
        } sigval_t;
        */

        //union sigval signalValue; 同下
        sigval_t signalValue;
        signalValue.sival_int = 256;
        sleep(2);

        //给父进程发送SIGINT信号
        sigqueue(getppid(),SIGINT,signalValue);
    }

    pause();

    return 0;
}


目录
相关文章
|
25天前
|
监控 算法 Linux
Linux内核锁机制深度剖析与实践优化####
本文作为一篇技术性文章,深入探讨了Linux操作系统内核中锁机制的工作原理、类型及其在并发控制中的应用,旨在为开发者提供关于如何有效利用这些工具来提升系统性能和稳定性的见解。不同于常规摘要的概述性质,本文将直接通过具体案例分析,展示在不同场景下选择合适的锁策略对于解决竞争条件、死锁问题的重要性,以及如何根据实际需求调整锁的粒度以达到最佳效果,为读者呈现一份实用性强的实践指南。 ####
|
25天前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
5月前
|
Ubuntu Linux vr&ar
IM跨平台技术学习(十二):万字长文详解QQ Linux端实时音视频背后的跨平台实践
本文详细记录了新版QQ音视频通话在 Linux 平台适配开发过程中的技术方案与实现细节,希望能帮助大家理解在 Linux 平台从 0 到 1 实现音视频通话能力的过程。
201 2
|
1月前
|
关系型数据库 MySQL Linux
Linux环境下MySQL数据库自动定时备份实践
数据库备份是确保数据安全的重要措施。在Linux环境下,实现MySQL数据库的自动定时备份可以通过多种方式完成。本文将介绍如何使用`cron`定时任务和`mysqldump`工具来实现MySQL数据库的每日自动备份。
121 3
|
2月前
|
监控 Linux 云计算
Linux操作系统在云计算环境中的实践与优化###
【10月更文挑战第16天】 本文探讨了Linux操作系统在云计算环境中的应用实践,重点分析了其在稳定性、安全性和高效性方面的优势。通过具体案例,阐述了Linux如何支持虚拟化技术、实现资源高效分配以及与其他开源技术的无缝集成。文章还提供了针对Linux系统在云计算中的优化建议,包括内核参数调整、文件系统选择和性能监控工具的应用,旨在帮助读者更好地理解和应用Linux于云计算场景。 ###
64 3
|
2月前
|
Ubuntu Linux
Linux实践|设置静态 IP 地址
Linux实践|设置静态 IP 地址
76 0
Linux实践|设置静态 IP 地址
|
4月前
|
存储 人工智能 数据管理
深入理解Linux操作系统之文件系统管理探索人工智能:从理论到实践的旅程
【8月更文挑战第30天】在探索Linux的无限可能时,我们不可避免地会遇到文件系统管理这一核心话题。本文将深入浅出地介绍Linux文件系统的基础知识、操作命令及高级技巧,帮助你更有效地管理和维护你的系统。从基础概念到实践应用,我们将一步步揭开Linux文件系统的神秘面纱。
|
4月前
|
Linux 调度
Linux0.11 信号(十二)(下)
Linux0.11 信号(十二)
41 1
|
4月前
|
存储 Linux 调度
|
4月前
|
存储 Unix Linux
Linux0.11 信号(十二)(上)
Linux0.11 信号(十二)
40 0