信号集与阻塞信号

linux常见的信号

信号是一种软件中断,是一种处理进程间异步的通信机制。信号可以导致一个正在运行的进程被另一个异步进程中断,转而处理某一个突发事件。
常见的信号

kill -l 命令查看
1) SIGHUP    2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP
 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR
31) SIGSYS  

通常对于一个进程发送信号时

  • 对于一个进程即便没有收到信号,它也直到怎样去检测处理它。
  • 操作系统向一个进程发送信号,实际上去修改了目标文件pcb中信息字段。
  • 当一个进程到信号时并不会立即去处理,而是在合适的时候(从内核态切换到用户态)。
  • 进程检测自己收到信号是因为自己pcb中信息字段设置未有效(从0置为1)

信号的产生

  • 用户在终端按下某些组合键(会被操作系统解释为信号),终端驱动程序会发送信号给前台程序。

//用一个简单的死循环验证,当按下组合键ctrl-c时,就是向该进程发送了一个信号,终止该进程。
#include<stdio.h>
int main()
{
    while(1)
    {
    printf("pid is %d\n",getpid());
    sleep(1);
turn 0;

}
  • 硬件异常产生信号。例如进程执行了除0的指令,cpu的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。还有执行了一个无法存储访问的进程产生一个SIGSEGV
#include<stdio.h>
int main()
{

    int a=10;
    int b=a/0;
    printf("b=%d\n",b);
    return 0;
}
//进行了除0的操作,硬件异常产生信号SIGFPE,进程异常退出

进程运行后异常退出,并显示core dumped。
core dumped:表示一个进程异常退出,操作系统会将异常信息转储到硬盘上,是便于gdb调试。
- 终止进程信号。进程调用kill函数可以发生信号给另一个进程,也可以kill命令发送信号给某个进程。

//任意进程之间发送任意信号
 #include <sys/types.h>
       #include <signal.h>
  int kill(pid_t pid, int sig);
//pid是传递信号的进程号,sig为发送的信号值
//一个进程给自己发送任意信号
#include <signal.h>
int raise(int sig)
//一个进程给自己发送唯一信号
 #include <stdlib.h>
 void abort(void);
  • 软件异常产生信号。当检测到某种软件条件已经发生,并将其通知有关进程时也会产生信号。
//特定时间后给进程发送信号(SIGALRM),该信号的默认动作是终止该进程
 #include <unistd.h>
 unsigned int alarm(unsigned int seconds);
//函数的返回值是0或设定的闹钟剩余的秒数

信号的处理

  • 忽略此信号。
  • 执行该信号的默认处理动作
  • 自定义捕捉。提供一个信号处理函数,要求内核在处理信号时切换到用户态执行这个处理函数。
#include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);
//信号处理函数,第一个参数为接收到的信号,第二个参数函数指针使接收到信号后处理代码入口。

阻塞信号

  • 信号递达(Delivery):实际执行信号的处理动作。
  • 信号未决(pending):信号从产生到递达之间的状态。
  • 信号阻塞(block):产生信号,信号也不会被递达。被阻塞的信号产生时将保持在未决状态,信号被阻塞了就不被递达。
    未决和阻塞标志可以用相同的数据类型sigset_t存储,sigset_t称为信号集
    信号在内核中的示意图
    这里写图片描述
    信号产生时,内核在该进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。
    特点
  • 信号未阻塞也未产生,当它递达时执行默认处理动作
  • 信号产生但被阻塞,所以暂时不能递达。尽管处理动作时忽略,但是在解除阻塞之前还不能忽略该信号,因为进程仍有机会改变对信号的处理动作之后再解除阻塞。

信号集操作函数

  #include <signal.h>

 int sigemptyset(sigset_t *set);
 //对set指向的信号集进行初始化,使所有信号的清空,即没有任何信号再集合中
   int sigfillset(sigset_t *set);
//用来填空填空信号集,即阻塞所有信号
   int sigaddset(sigset_t *set, int signum);
//将某个信号添加到信号集,第一个参数为添加的信号集,第二个为添加的信号  
int sigdelset(sigset_t *set, int signum);
//从信号集中删除某个信号
int sigismember(const sigset_t *set, int signum);
//检测信号集是否为空
 #include <signal.h>
 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
 //读取或改变进程的信号屏蔽字。成功返回0,失败则返回-1.
 如果oldset非空,则读取进程当前的信号屏蔽字通过oldset传出。如果set非空,则更改进程的信号屏蔽字,参数how表示如何更改。如果set和oldset都非空,则先将原来的屏蔽字备份到oldset,再根据set和how参数更改屏蔽字。

how含义

  1. SIG_BLOCK:将第二个参数所描述的集合添加到当前进程阻塞的信号中
  2. SIG_UNBLOCK:将第二个参数锁描述的集合从当前的进程阻塞的信号集中删除
  3. SIG_SETMASK:无论之前的阻塞号。设置当前进程阻塞的集合的第二个参数描述的对象
 #include <signal.h>
 int sigpending(sigset_t *set);
//读取当前进程的未决信号集,通过set参数传出。成功返回0,失败返回-1
#include <signal.h>

int sigpending(sigset_t *set);
//读取当前的未决信号,通过set传出

代码实现:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void printsigset(sigset_t *set)
{
    int i=0;
    for(i=1;i<=31;i++)
    {
        if(sigismember(set,i))//检测该信号是否存在与
        {
        printf("1");
        }
        else
        {
        printf("0");
        }
    }
    printf("\n");

}
void handler(int sig)
{
    printf("get a sig%d\n",sig);

}
int main()
{
    sigset_t blockset,oblockset,pending;
//定义三个信号集,其中pending是用来获取未决信号集的
    sigemptyset(&blockset);
    sigemptyset(&oblockset);//将blocket,oblocket初始化清空置零
    sigaddset(&blockset,2);//将2号信号添加到blocket信号集中
    signal(2,handler);
    sigprocmask(SIG_SETMASK,&blockset,&oblockset);//将2号信号block阻塞,将原来的值读到oblockset
    int count=0;
    while(1)
    {
        sigpending(&pending);//获取当前的未决信号
        printsigset(&pending);//并显示出来
        sleep(1);
        if(++count==10)
        {
            //printf("recover proc block set\n",count)

            sigprocmask(SIG_SETMASK,&oblockset,NULL);//当count加到10时,对pending表进行操作,当前的屏蔽字为oblockset对应的信号集,也就是清除对2号信号的阻塞,也就还原回去。

        }
    }
}

这里写图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值