Linux进程间通信(二)之信号

Linux-C 进程通信之信号

一、简述

      记--进程之间使用信号进行通信。异步信号包含: 非实时信号 、实时信号。

       实时信号一定会响应,非实时信息号不一定会响应(可能会被忽略,或丢失)

     信号一般有以下设定:
            1,捕捉    (收到某个信号,做指定的动作,而不是做默认的)
            2,忽略    (收到某个信号,不做什么动作)
            3,阻塞    (收到某个信号,先做完当前事情,然后在响应信号)
            4,按照默认动作

     注:SIGKILL,SIGSTOP不能被捕捉

       关于信号的详细说明请参考man手册:man  7  signal。

二、signal()与kill()

signal()函数
    功能
            简单的信号处理函数(信号捕捉函数)
        头文件
            #include <signal.h>
        原型
            
            typedef void (*sighandler_t)(int); //信号处理函数的 指针

            sighandler_t signal(int signum, sighandler_t handler);
            
        参数
            
            signum:要捕捉的信号

            handler:处理方式

                           1、SIG_IGN:忽略这个信号
                           2、SIG_DFL:按照默认动作执行这个信号
                           3、如果是一个函数,则是捕捉这个信号,收到这个信号的时候去执行这个函数。

                            
            
        返回值
            
            成功:返回信号处理程序的先前值

            出错:返回SIG_ERR,并设置errno
        

kill()函数
    功能
            向一个进程发送信号
        头文件
            #include <sys/types.h>
            #include <signal.h>
        原型
            int kill(pid_t pid, int sig);
        参数
            
            pid:进程ID  (process id)

            sig:要发送的信号   
            
        返回值
            
            成功:返回0

            失败:返回-1,并设置error。     

三、sigprocmask()信号的阻塞

         信号的阻塞:在阻塞过程中,信号不会丢失,会被挂起,等解开阻塞的时候再响应。

       

sigprocmask()函数
    功能
            阻塞信号,延迟响应 。(检查并更改阻塞的信号)
        头文件
            #include <signal.h>
        原型
            int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
        参数
            
            how:对信号的操作(应用于信号集合中的所有函数)

                      SIG_BLOCK:添加信号集合里面的信号进行阻塞(原本的设置上添加设置)
                      SIG_UNBLOCK:解除信号集合里面的信号的阻塞。
                      SIG_SETMASK: 直接阻塞信号集合里面的信号,原本的设置直接被覆盖。

            set:要设置的信号集合
                        int sigemptyset(sigset_t *set);//清空信号集合
                        int sigfillset(sigset_t *set);//将所有信号登记进集合里面
                        int sigaddset(sigset_t *set, int signum);//往集合里面添加signum信号
                        int sigdelset(sigset_t *set, int signum);// 往集合里面删除signum信号
                        int sigismember(const sigset_t *set, int signum);//测试信号集合里面有无signum信号

            oldset:用来保存旧的信号集合设置
                        如果这里是一个具体的指针,则将原本的设置保存在这里
                        如果是NULL则不保存。
            
        返回值
            
            成功:返回0

            失败:返回-1,并设置error
            
        备注
            在阻塞状态时,非实时信号可能会丢失
 

四、带数据的信号的发送与处理:sigaction()与sigqueue()

sigaction()函数
    功能
            检查并改变信号动作(捕捉信号,指定处理动作)
        头文件
            #include <signal.h>
        原型
            int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
        参数
            
            signum:捕捉的信号

            act:信号动作结构体,用来登记对这个信号进行处理的动作。

                      

                struct sigaction 
                {
                   void     (*sa_handler)(int);    //不带参数的信号处理函数,默认执行这个不带参数的信号处理函数
                   void     (*sa_sigaction)(int, siginfo_t *, void *);//带参的信号处理函数,如果想要使能这个信号处理函数,
                                                                     //需要设置一下sa_flags为SA_SIGINFO
                   sigset_t   sa_mask;        //信号阻塞设置
                                                         //1,在信号处理函数执行的过程当中阻塞掉指定的信号,

                                                                 //指定的信号过来将会被挂起,等函数结束后再执行
                                                         //2,sigset_t信号集合类型,参照sigprocmask中sigset的使用方式。

            
                   int        sa_flags;        //信号的操作标识,例如设置使用的是带参信号处理函数,还是不带参数的
                   void     (*sa_restorer)(void);    //被遗弃的设置
                };

            oldact:用来保存原来的设置,如果是NULL则不保存。
            
        返回值
            
            成功:返回0

            失败:返回-1,并设置error
            
        备注
            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) */
                           void    *si_lower;     /* Lower bound when address violation
                                                     occurred (since Linux 3.19) */
                           void    *si_upper;     /* Upper bound when address violation
                                                     occurred (since Linux 3.19) */
                           int      si_pkey;      /* Protection key on PTE that caused
                                                     fault (since Linux 4.6) */
                           void    *si_call_addr; /* Address of system call instruction
                                                     (since Linux 3.5) */
                           int      si_syscall;   /* Number of attempted system call
                                                     (since Linux 3.5) */
                           unsigned int si_arch;  /* Architecture of attempted system call
                                                     (since Linux 3.5) */
            };
         

sigqueue函数
    功能
            将信号和数据发送到指定进程
        头文件
            #include <signal.h>
        原型
            int sigqueue(pid_t pid, int sig, const union sigval value);
        参数
            
            pid:进程ID

            sig:要发送的信号

            value:附加数据

                       union sigval 
                       {
                            int   sival_int;//只附加一个int数据
                            void *sival_ptr;//附加更多数据(附加一个地址) 
                        };

                     //注:这是共用体、两者取其一
                    
            
        返回值
            
            成功:返回0

            失败:返回-1,并设置error
            
        备注
            跟sigaction结合使用

五、补充

  1、查看进程相关信息

        ps:查看进程状态   (一个瞬间的进程状态,静态)
        top:“实时查看” ,按q退出    (实时动态显示)
        pstree  树状查看  (可以看出所属子进程)   

       

 2、对某个进程发送信号

    kill  -s   指定发送一个信号      进程的pid
    killall:指定一个应用程序名字去发送信号

    kill  -l   查看系统有什么信号 

   

其中SIGKILL,SIGSTOP只能按照系统默认动作执行,不能捕捉,阻塞及忽略

前面31个是非实时信号:
                1,每一个非实时信号对应一个信号名
                2,每一个非实时信号基本上都会对应一个系统事件
                3,信号有可能会丢失

后面的31个是实时信号:
               1,信号不会丢失
               2,优先级比非实时信号要高

2、信号发送:
    1,自己发给自己: raise()函数
    2,发送信号给其他进程:
              kill -s 信号 进程号
              killall -s 信号 进程名字


3、信号的继承
    1,信号初始化的设置是会被子进程继承的
    2,信号的阻塞设置是会被子进程继承的
    3,被挂起的信号是不会被子进程继承的

4、信号处理函数里面应该注意的地方:
    1,不应该在信号处理函数里面操作全局变量(如果要操作,记得加锁)
    2,应该注意一下一些函数调用是否安全,可以查看man 7 signal

5、测试所有信号的响应优先级

        实时信号34-64:数字大的优先响应;


原文链接:https://blog.csdn.net/nanfeibuyi/article/details/81945408

发布了9 篇原创文章 · 获赞 5 · 访问量 2206

猜你喜欢

转载自blog.csdn.net/CSDN_liu_sir/article/details/102623033