天天看点

Linux信号集

信号集的函数:

类型:sigset_t 类型

/****************************
 *功能:把一个信号集的内容清空
 *参数:sigset_t *set:是一个信号集,sigset_t的类型一定是可以容纳所有的信号的个数
 *返回值:成功返回0,失败返回-1
 * ************************/
int sigemptyset(sigset_t *set);

/****************************
 *功能:把一个信号集的内容填满,包含所有的信号
 *参数:sigset_t *set:是一个信号集,sigset_t的类型一定是可以容纳所有的信号的个数
 *返回值:成功返回0,失败返回-1
 * ************************/
int sigfillset(sigset_t *set);


/****************************
 *功能:把一个信号添加到信号集中
 *参数:sigset_t *set:是一个信号集,sigset_t的类型一定是可以容纳所有的信号的个数
 *返回值:成功返回0,失败返回-1
 * ************************/
int sigaddset(sigset_t *set, int signum);

/****************************
 *功能:把一个信号从信号集中删除
 *参数:sigset_t *set:是一个信号集,sigset_t的类型一定是可以容纳所有的信号的个数
 *返回值:成功返回0,失败返回-1
 * ************************/
int sigdelset(sigset_t *set, int signum);

/****************************
 *功能:判断是否是信号是否在指定集合中
 *参数:sigset_t *set:是一个信号集,sigset_t的类型一定是可以容纳所有的信号的个数
 *返回值:成功返回0,失败返回-1
 * ************************/
int sigismember(const sigset_t *set, int signum);      

sigprocmask函数:

用来读取或者更改进程的信号屏蔽集。

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

如果 set 为空 oldset 不为空, 则会将进程原来的信号屏蔽集传出;

如果 set 不为空,oldset 为空, 则会根据 how 参数的指示修改进程的信号屏蔽集;

如果两个指针都不为空, 则先备份原来的信号屏蔽字到 oldset, 然后根据 how参数修改。

how参数有如下函数

含义
SIG_BLOCK 屏蔽信号,添加的信号屏蔽字不覆盖之前的,这是一个并集的关系 
SIG_UNBLOCK 希望解除BLOCK的信号集合。
SIG_SETMASK 该进程的信号屏蔽是set指向的值。

注意到这里后两个参数,​

​set​

​​用以设置新的信号屏蔽字,​

​oldset​

​返回当前信号屏蔽字。

如果不进行设置,仅仅只是想得到当前的信号屏蔽字,那么前两个参数也就没有意义了。

sigprocmask(0,NULL,&sigset);

sigpending函数:

int sigpending(sigset_t *set);

函数说明:sigpending()会将被阻塞的信号集合由参数set 指针返回.

返回值:执行成功则返回 0, 如果有错误则返回-1.

简单程序实例:

程序运行时,每秒打印一此未决状态信号集,初始全为0,当输出ctrl-c时, 由于我们阻塞了SIGINT信号, 会使该信号处于未决状态。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pwd.h>
#include <signal.h>

// 打印信号集
void 
printsigset(const sigset_t *set)
{
    int i = 0;
    for(; i<6; ++i)
    {
        if(sigismember(set, i) == 1)
            printf("signal[%d] = 阻塞\n", i);
        else
            printf("signal[%d] = 未阻塞\n", i);
    }
    printf("\n");
}

int 
main()
{
    sigset_t s;
    sigemptyset(&s); // 初始化
    sigaddset(&s, SIGINT);  //添加SIGINT,
    sigprocmask(SIG_BLOCK, &s, NULL );  //把当前信号集 s 变为 屏蔽信号集,
                    //这个信号集里的信号会被阻塞
    while(1)
    {
        sigpending(&s);
        printsigset(&s);
        sleep(3);
    }

    return 0;
}      

结果:

Linux信号集
Linux信号集

该程序的运行结果如下, 可以看见, 在信号处于阻塞状态时, 所发出的信号对进程不起

作用, 并且该信号进入待处理状态。 读者按任意键, 并且信号脱离了阻塞状态后, 用户发出

的信号才能正常运行。 这里 SIGINT 已按照用户自定义的函数运行, 请读者注意阻塞状态下

SIGINT 的处理和非阻塞状态下 SIGINT 的处理有何不同。

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pwd.h>
#include <signal.h>

/* 自定义的信号处理函数 */
void my_func(int signum)
{
  printf("If you want to quit,please try SIGQUIT\n");
}
int main()
{
  sigset_t set;
  sigset_t pendset;
  struct sigaction action1;
  struct sigaction action2;
  /* 初始化信号集为空 */
  if (sigemptyset(&set) < 0)
  {
    perror("sigemptyset");
    exit(1);
  } /* 将相应的信号加入信号集 */
  
  if (sigaddset(&set, SIGQUIT) < 0)
  {
    perror("sigaddset");
    exit(1);
  } 
  
  if (sigaddset(&set, SIGINT) < 0)
  {
    perror("sigaddset");
    exit(1);
  } 
  
  if (sigismember(&set, SIGINT))
  {
    sigemptyset(&action1.sa_mask);
    action1.sa_handler = my_func;
    action1.sa_flags = 0;
    sigaction(SIGINT, &action1, NULL);  //注册函数
  } 
  if (sigismember(&set, SIGQUIT))
  {
    sigemptyset(&action2.sa_mask);
    action2.sa_handler = SIG_DFL;
    action2.sa_flags = 0;
    sigaction(SIGQUIT, &action2,NULL);  //注册函数
  } 
  /* 设置信号集屏蔽字, 此时 set 中的信号不会被传递给进程, 暂时进入待处理状态 */

  if (sigprocmask(SIG_BLOCK, &set, NULL) < 0)
  {
    perror("sigprocmask");
    exit(1);
  }else
  {
    printf("Signal set was blocked, Press any key!");
    //getchar();  /*按下键后就会执行信号函数*/
  } 
  /* 在信号屏蔽字中删除 set 中的信号 */
  if (sigprocmask(SIG_UNBLOCK, &set, NULL) < 0)
  {
    perror("sigprocmask");
    exit(1);
  }else
  {
    printf("Signal set is in unblock state\n");
  } 
  while(1);
  exit(0);
}      

结果:

# ./a.out 

Signal set was blocked, Press any key!^C^C^C    //按下多次ctr+c,但只处理一次

If you want to quit,please try SIGQUIT

Signal set is in unblock state                                /* 从信号屏蔽字中删除 set 中的信号 */

^CIf you want to quit,please try SIGQUIT           /* 非阻塞状态下 SIGINT 的处理 */

^CIf you want to quit,please try SIGQUIT