zoukankan      html  css  js  c++  java
  • First step to Signal —— in Linux C Programing

    1. What's signal

    信号是软件中断,提供了一种处理异步事件的方法。(见《Unix环境高级编程》)一般使用时需包含 signal.h 库。

    每个信号命名由SIG开头,实际值为正整数。(不存在编号为0的信号,0有特殊用途)

    具体信号列表卡参见《Unix环境高级编程》 或者 


    2. signal 函数

    信号机制最基础的接口是signal函数,声明如下:

    1 // Original Definition
    2 void ( *signal(int signum, void (*handler)(int)) ) (int);
    3 
    4 // Readable Definition
    5 typedef void (*sighandler_t)(int);
    6 sighandler_t signal(int signum, sighandler_t handler); 

    第二行是最原始的表示方法,利用typedef我们可提高可读性,得到第5和6行的声明。

    一般带有指针的handler都代表一个处理函数的指针。

    由line 6 我们可得知,signal函数表示将一个参数为信号的函数handler注册到一个信号上,即一旦触发该信号,该信号就会作为参数传给函数handler立即执行。或者说,信号一旦触发,该函数handler就会捕捉该信号,覆盖掉系统默认动作。(有一些如SIGSTOP等的信号不可被捕捉或忽略)

     1 #include <stdio.h> 
     2 #include <stdlib.h>  
     3 #include <signal.h>  
     4 
     5 
     6 void handler(int sig) {
     7     printf("
    Signal comes!
    "); 
     8 }  
     9 
    10 int main() {  
    11     printf("pid:%ld
    ",(long)getpid()); 
    12     signal(SIGINT, handler); 
    13 
    14     getchar();
    15 
    16     return 0;  
    17 
    18 }  

    执行上列程序,输入时按ctrl+c(SIGINT中断条件)试试?


    3. kill 和 raise

    定义如下

    1 int kill(pid_t pid, int signo); 
    2 int raise(int signo);
    3 
    4 /* 两者关系 */
    5 pid_t self = getpid();
    6 
    7 raise(signo) == kill(self, signo);

    kill函数是当前进程将信号发给对应的进程pid,而raise则是当前进程向自身发信号。(因此有上面的等式)

    kill的pid参数有以下情况:

    • pid > 0        将信号发送给pid进程
    • pid == 0      将信号发送给与当前进程属于同一进程组的所有进程
    • pid < 0        将信号发送给(-pid)进程组,前提是当前进程有权限向其发送信号
    • pid == -1    将信号发送给所有当前进程有权限发送信号的进程
     1 #include <stdio.h> 
     2 #include <stdlib.h>  
     3 #include <signal.h>  
     4 
     5 
     6 void handler(int sig) {
     7     printf("
    Signal comes!
    "); 
     8 }  
     9 
    10 int main() {  
    11     printf("pid:%ld
    ",(long)getpid()); 
    12     signal(SIGINT, handler); 
    13 
    14  // raise(SIGINT);
    15     kill(getpid(), SIGINT);
    16 
    17     return 0;  
    18 
    19 }  

    注释可以互换一下,结果是一样的。


    4. 信号集

    信号集可以理解成多个信号的集合。

    常用的函数如下:

    1 int sigemptyset(sigset_t *set);    // 置空集合
    2 int sigfillset(sigset_t *set);           // 使set包括所有信号
    3 int sigaddset(sigset_t *set, int signo);    // 将信号添加到集合
    4 int sigdelset(sigset_t *set, int signo);    // 将信号从集合中删除
    5 // 以上函数成功返回 0, 错误返回 -1
    6 
    7 int sigismamber(const sigset_t *set, int signo);    // 判断信号是否在集合中
    8 // 以上函true返回1, false返回0,出错返回-1

    5. sigaction 

    sigaction 既是一个函数的名字也是一个结构体的名字,他们的定义分别如下:

    int sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
    // 成功返回0,出错返回-1
    
    struct sigaction {
        void (*sa_handler)(int);  // 信号处理函数
        sigset_t sa_mask;     // 作为该信号集合的标识
        int sa_flags;
        /* alter handler */
        void (*sa_sigaction)(int, siginto_t *, void *);
    }

    【待定】


    6. 信号阻塞

    sigprocmask 函数

    1 int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
    2 // 成功返回0,出错返回-1

    how 参数有三种选择:

    • SIG_BLOCK        相当于set 与 oset的并集作为阻塞信号,set为新添加想要阻塞的信号。 相当于&mask = &oset , mask = set | oset
    • SIG_UNBLOCK    相当于¬set 与 oset的交集作为阻塞信号,set为想要解除信号的集合。 相当于&mask = &oset ,  mask = ~set & oset
    • SIG_SETMASK    新阻塞集合直接等于set的集合。相当于 &mask = &oset, mask = set

    如果 set 为 NULL, 则不会改变当前进程的信号屏蔽字,how取值无意义。有时利用这点用来取得当前进程阻塞信号的集合变量。

     1 #include <stdio.h>
     2 #include <signal.h>
     3 
     4 void check() {
     5     sigset_t set;
     6     printf("====START
    ");
     7     if(sigprocmask(0, NULL, &set)<0)
     8     {
     9         printf("Sigprocmask error!!
    ");
    10         exit(-1);
    11     }
    12     if(sigismember(&set,SIGINT))
    13         printf("sigint
    ");
    14 
    15     printf("====END
    ");
    16 
    17 }
    18 
    19 void handler() {
    20     printf("
    Signal comes!
    ");
    21 }
    22 
    23 int main() {
    24     sigset_t blockset, oldblockset;
    25 
    26     signal(SIGINT, handler); 
    27 
    28     sigemptyset(&blockset); 
    29     
    30     check();
    31 
    32 
    33     sigaddset(&blockset,SIGINT);
    34     check();
    35     
    36     sigprocmask(SIG_SETMASK,&blockset,&oldblockset); 
    37     check();
    38     
    39     sigprocmask(SIG_SETMASK,&oldblockset,NULL); // clear mask set
    40     check();
    41     
    42     return 0;
    43 }

    运行结果:


  • 相关阅读:
    测量MySQL的表达式和函数的速度
    MySQL中的比较操作符<=>
    Python中的args和kwargs
    MySQL8新特性(2)--mysql的升级过程
    MySQL8新特性(1)--原子DDL
    PostgreSQL中的一些日志
    PostgreSQL的表空间
    [九]基础数据类型之Boolean详解
    [八]基础数据类型之Double详解
    [七]基础数据类型之Float详解
  • 原文地址:https://www.cnblogs.com/lhfcws/p/3234832.html
Copyright © 2011-2022 走看看