信号

一、信号的初步认识

1、特点

  • 简单
  • 携带的信息量少
  • 使用在某个特定的场景中

2、信号的状态

  • 产生
    • 键盘:ctrl + c
    • 命令:kill
    • 系统函数:kill
    • 软条件:定时器
    • 硬件:段错误,除0错误
  • 未决状态 -- 没有被处理
  • 递达 - 信号被处理了
    • 忽略
    • 捕捉
    • 执行了默认动作

3、阻塞信号集、未决信号集

    阻塞信号集合未决信号集在pcb中,用户不能直接操作,阻塞信号集里存放的是要屏蔽的信号,如果不想让进程处理某个信号就可以将该信号放入阻塞信号集里。

       没有被处理的信号的集合叫未决信号集。

二、信号相关函数

1、kill -- 发送信号给指定进程

函数原型:

int kill(pid_t pid, int sig);

pid参数:

       pid = 0;发送信号给与调用kill函数进程属于同一进程组的所有进程

       pid < -1; 取|pid|发给对应进程组

       pid = -1;发送给进程有权限发送的系统中所有进程

示例:

# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <signal.h>

int main()
{
    pid_t pid = fork();
    if(pid > 0)
    {
        while(1)
        {
            printf("paren pid = %d",getpid());
            sleep(1);
        }
    }
    else if(pid == 0)
    {
        sleep(3);
        kill(getppid(),SIGKILL);
    }
    return 0;
}

2、raise -- 自己给自己发信号

函数原型:

int raise(int sig);

示例:

# include <stdio.h>
# include <signal.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/wait.h>
int main()
{
    pid_t pid = fork();
    if(pid > 0)
    {
        int s;
        pid_t wpid = wait(&s);
        printf("child died pid = %d\n",wpid);
        if(WIFSIGNALED(s))
        {
            printf("died by signal:%d\n",WTERMSIG(s));
        }
    }
    else if(pid == 0)
    {
        raise(SIGINT);
    }
}

3、abort -- 给自己发送异常终止信号

6号信号:SIGABORT--调用abort函数时产生该信号,终止进程并产生core文件。

函数原型:

void abort(void);
没有参数,没有返回值,永远不会调用失败。

示例;

# include <stdio.h>
# include <signal.h>
# include <stdlib.h>
# include <unistd.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/wait.h>
int main()
{
    pid_t pid = fork();
    if(pid > 0)
    {
        int s;
        pid_t wpid = wait(&s);
        printf("child died pid = %d\n",wpid);
        if(WIFSIGNALED(s))
        {
            printf("died by signal:%d\n",WTERMSIG(s));
        }
    }
    else if(pid == 0)
    {
        while(1)
        {
            abort();
        }
    }
}

4、闹钟

  • alarm--设置定时器(每个进程只有一个定时器),使用自然定时法,不受进程状态影响
  • 14号信号:SIGALRM--定时器超时,超时的时间有alarm系统调用设置,信号的操作是终止进程。

函数原型:

unsigned int alarm(unsigned int seconds);
//函数返回上一次闹钟剩余时间,如果是第一次设置闹钟则返回0

示例:

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

int main()
{
    int ret = alarm(5);
    printf("ret = %d\n",ret); //ret为0,因为是第一次设置闹钟

    ret = alarm(2); //ret为5,因为第二次设置的闹钟覆盖了第一次设置的闹钟,第一次闹钟剩余时间还剩5
    printf("ret = %d\n",ret);

    while(1)
    {
        printf("hello world\n");
        sleep(1);
    }
    return 0;
}

5、setitimer -- 定时器,并实现周期性定时

函数原型:

int setitimer(int which, 
              const struct itimerval *new_value, 
              struct itimerval *old_value);
which:定时法则
        1、ITIMER_REAL
        2、ITIMER_VIRTUAL
        3、ITIMER_PROF
struct itimerval
{
    struct timeval it_interval;    //定时器循环周期
    struct timeval it_value;       //第一次触发定时器的时间
};

struct timeval
{
    time_t tv_sec;    //秒
    suseconds_t tv_usec;    //微秒
};

示例:

# include <stdio.h>
# include <sys/time.h>
# include <unistd.h>

int main()
{
    struct itimerval new_value;
    new_value.it_value.tv_sec = 2;
    new_value.it_value.tv_usec = 0;

    new_value.it_interval.tv_sec = 1;
    new_value.it_interval.tv_usec = 0;

    setitimer(ITIMER_REAL,&new_value,NULL);

    while(1)
    {
        printf("hello world\n");
        sleep(1);
    }
    return 0;
}

三、信号集

1、概念

  • 未决信号集:没有被当前进程处理的信号
  • 阻塞信号集:将某个信号放到阻塞信号集,这个信号就不会被处理,阻塞解除之后,信号被处理

2、信号处理流程

  1. 信号产生,信号处于未决状态,进程收到信号之后,信号被放入未决信号集
  2. 放入未决信号集中的信号等待处理,在处理之前需要做一件事情:判断阻塞信号集中该信号对应的标志位是否为1,如果为1,不处理,如果为0,处理该信号

 

3、自定义信号集

  • int sigemptyset(sigset_t *set);将set集合置空
  • int sigfillset(sigset_t set);将所有信号加入set集合
  • int sigaddset(sigset_t *set,int signo);将signo信号加入到set信号集
  • int sigdelset(sigset_t *set,int signo);从set集合中移除signo信号
  • int sigismember(const sigset_t *set,int signo);判断信号是否存在

4、sigprocmask函数

作用:屏蔽and杰出信号屏蔽,将自定义信号集设置给阻塞信号集

函数原型:int sigproxmask(int how,const sigset_t,sigset_t *oldset);

参数how:

  • SIG_BLOCK:当how设置为此值,set表示需要屏蔽的信号。相当于mask = mask | set
  • SIG_UNBLOCK:当how设置为此值,set表示需要解除屏蔽的信号。相当于mask = mask & ~set
  • SIGSETMASK:当how设置为此值,set表示用于替代原始屏蔽集的新屏蔽集。相当于mask = set。若调用sigprocmask解除了对当前若干个信号的阻塞,则在sigprocmask返回前,至少其中一个信号递达。

5、sigpending -- 读取当前进程未决信号集

函数原型:int sigpending(sigset_t set);

参数:set  --  内核将未决信号集写入set

6、示例

  • 设置阻塞信号集并读取当前进程的未决信号集
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <signal.h>

int main()
{
    //定义自定义信号集变量
    sigset_t myset;
    //自定义信号集置空
    sigemptyset(&myset);
    //添加要屏蔽的信号
    sigaddset(&myset,SIGINT);
    sigaddset(&myset,SIGQUIT);
    sigaddset(&myset,SIGKILL);
    //修改内核中阻塞信号集
    sigprocmask(SIG_BLOCK,&myset,NULL);
    //每隔一秒读取阻塞信号集
    while(1)
    {
        sigset_t pengset;
        sigpending(&pengset);
        int i = 0;
        for(i = 1; i < 32; i++)
        {
            if(sigismember(&pengset,i))
            {
                printf("1");
            }
            else
            {
                printf("0");
            }
        }
        printf("\n");
        sleep(1);
    }
    return 0;
}

四、信号捕捉

1、signal函数

  • typedef void (*sighandler_t)(int);
  • sighandler_t signal(int signum, sighandler_t handler);

2、sigaction函数

函数原型:

int sigaction(int signum,    //捕捉的信号
              const struct sigaction *act,
              struct sigaction *oldact    //一般置NULL);

struct sigaction
{
    void (*sa_handler)(int);    //捕捉到信号后对应的操作
    void (*sa_sigaction)(int,siginfo_t*,void*);    //无需做处理
    sigset_t sa_mask;    //在信号处理函数执行过程中,临时屏蔽指定的信号
    int sa_flags;    //0
    void (*sa_restorer)(void);    //以废弃,不用做处理
}

示例:

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

int main()
{
    //捕捉到信号所做的操作
    void myfunc(int no)
    {
        printf("hello world");
        sleep(3);
    }
    //定义 sigaction函数的第二个参数变量
    struct sigaction act;
    //设置sigaction函数第二个参数结构体中各个参数
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    //设置在myfunc函数执行过程中要屏蔽的信号
    sigaddset(&act.sa_mask,SIGQUIT);
    act.sa_handler = myfunc;

    //捕捉信号
    sigaction(SIGINT,&act,NULL);

    while(1)
    {
        printf("run\n");
        sleep(1);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值