操作系统——信号(2)

操作系统中,信号的产生可以告诉系统要去执行某个操作。操作系统中有默认的信号处理函数。我们也可以更改默认的信号处理函数,由我们自己写。——信号捕捉

我们先来看看信号在内核中是怎样的:
这里写图片描述

信号对于操作系统来说,分为3类:
1.阻塞信号
2.未决信号
3.忽略

每个信号都有两个标志位分别为阻塞(block)和未决(pending),还有一个函数指针表示处理动作。
信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清楚该标志。

ps:Linux中,常规信号在递达之前产生多次只计一次。

我们看看信号集操作函数:

#include<signal.h>

//初始化set所指向的信号集,使其中所有信号集的对应bit清零
int sigemptyset(sigset_t *set);

//初始化set指向的信号集,该信号集表示系统支持的所有信号
int sigfillset(siget_t *set);

//添加某种信号
int sigaddset(siget_t *set,int signo);

//删除某种信号
int sigdelset(siget_t *set,int signo);

//判断set信号集有效信号中是否包含某种信号,返回值(bool类型)
int sigismember(const siget_t *set,int signo);

//读取或更改进程的信号屏蔽字(阻塞信号集)
int sigprocmask(int how,const sigset_t *set,sigget_t *oset)

//读取当前进程的未决信号集,set,输出型参数
sigpending(sigset_t *set);

函数使用例子:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>

void printfsigset(sigset_t *set)
{
    int i = 0;
    for(i=0;i<32;i++)
    {
        if(sigismember(set,i))        //判断信号是否在未决信号集中
        {
            putchar('1');
        }
        else{
            putchar('0');
        }
    }
    puts("");
}


int main()
{

    sigset_t s,p;    //信号集
    sigemptyset(&s);      //初始化阻塞信号集
    sigaddset(&s,SIGINT);   //添加信号

    sigprocmask(SIG_BLOCK,&s,NULL);   //设置到信号集中     

    while(1)
    {
        sigpending(&p);           //获取未决信号集
        printfsigset(&p);
        sleep(1);
    }
    return 0;
}

运行结果:
这里写图片描述

当我们 Ctrl + C 时,发送SIGINT 2号信号。但是我们设置为阻塞,未进行处理,所以在未决信号集中标着1,并没有递达。
我们按 Ctrl + \ 时,发送SIGQUIT,由于该信号并未阻塞,所以程序结束,段错误。

由于操作系统中对信号有默认的处理函数,我们希望产生某个信号的时候,处理函数由我们自己定义。
函数:

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

struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

act 和 oact指向的是sigaction结构体,signo是指定信号的编号。
将sa_handler赋值为常数SIGIGN传给sigaction表示忽略信号,
赋值为SIG_DFL表示指向系统默认函数,
赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函数。

简单例子:

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void sig_alrm(int signo)
{
    //do nothing
    /*
    int i = 0;
    for(i = 1; i < 6;i++)
    {
        printf("%d\n",i);
        sleep(1);
        fflush(stdout);
    }
    */
}


unsigned int mysleep(unsigned int nsecs)
{
    struct sigaction new,old;
    unsigned int unslept = 0;
    new.sa_handler = sig_alrm;      //自己定义的信号处理函数
    sigemptyset(&new.sa_mask);       //初始化信号集

    new.sa_flags = 0;
    sigaction(SIGALRM,&new,&old);       //SIGALRM 使用自己的定义函数

    alarm(nsecs);                    //定时器
    pause();

    unslept = alarm(0);              //清空定时器
    sigaction(SIGALRM,&old,NULL);       //恢复成默认的信函处理函数
    return unslept;
}


int main()
{
    while(1)
    {
        mysleep(5);
        printf("5 seconds passed\n");
    }
    return 0;
}

自己定义的sig_alrm() do nothing :
这里写图片描述

sig_alrm() to do:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/Shawei_/article/details/81394539