欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

信号的介绍及使用

程序员文章站 2024-01-24 08:59:46
...

1.什么是信号
(1)信号是内容受限制的一种异步通信机制
(2)信号的目的是用来通信
(3)信号是异步的(对比硬件中断)
(4)信号本质上是int型数字编号(事先定义好的)

2.信号由谁发出
(1)用户在终端按下按键
(2)硬件异常后由操作系统内核发出信号
(3)用户使用kill命令向其他进程发送信号
(4)某种软件条件满足后也会发出信号,如alarm闹钟时间到会产生SIGALARM信号,向一个读端已经关闭的管道write时会产生SIGPIPE信号

3.信号由谁处理、如何处理
(1)忽略信号
(2)捕捉信号(信号绑定了一个函数)
(3)默认处理(忽略或终止进程)

4.常见的信号介绍

(1)SIGINT 		2 		Ctrl+c时os送给前台进程组中每个进程
(2)SIGABRT		6		调用abort函数,进程异常终止
(3)SIGPOLL SIGIO 8		指示一个异步IO事件,在高级IO中用到
(4)SIGKILL		9		杀死进程的终极方法
(5)SIGGSEGV	11		无效访问储存时OS发出该信号
(6)SIGPIPE		13		涉及管道和socket
(7)SIGALARM	14		涉及alarm函数实现
(8)SIGTERM		15		kill命令发送的OS默认终止信号
(9)SIGCHLD		17		子进程终止或停止时OS向其父进程发此信号
(10)SIGUSR1		10		用户自定义信号,作用和意义由应用者自己定义
(11)SIGUSR2		12	

5.进程对信号的处理
(1)signal函数的介绍

typedef void (*sighandler_t)(int);	//函数指针
sighandler_t signal(int signum, sighandler_t handler);
参数1:注册一个信号处理方法
参数2:用一个函数来处理
返回值:返回值出错时为SIG_ERR,绑定成功返回旧的捕获函数

(2)用signal函数处理SIGINT信号
(2.1)默认处理(SIG_DFL)
(2.2)忽略处理(SIG_IGN)
(2.3)捕获处理(signal函数绑定一个捕获函数后信号发生后会自动执行绑定的捕获函数,并且把信号编号作为参数传给捕获函数)

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

typedef void (*sighandler_t)(int);

//捕获函数
void func(int sig)
{
        if(SIGINT != sig)
        {
                return;
        }
        printf("func for signal: %d\n",sig);
}

int main(void)
{
        sighandler_t ret = (sighandler_t)-2;

        //sighandler_t signal(int signum, sighandler_t handler);函数原型
        //signal(SIGINT,func);
        //signal(SIGINT,SIG_DFL);       //让信号默认处理
        ret = signal(SIGINT,SIG_IGN);   //忽略处理
        //ret = signal(SIGKILL,SIG_IGN);
        printf("返回值为:%d\n",(int)ret);
        if(SIG_ERR == ret)      //判断信号处理是否成功
        {
                perror("signal");
                exit(-1);
        }
        printf("before while(1)\n");
        while(1);
        printf("after while(1)\n");

        return 0;
}

6.signal函数的缺点和优点
(1)优点:简单好用,捕获信号常用
(2)缺点:无法简单直接得知之前设置的对信号的处理方法,可移植性差(当自己设置捕获函数时就无法移植)

7.sigaction函数介绍

int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
参数1:和signal一样
参数2:设置新的捕获函数
参数3:返回旧的捕获函数

(1)比signal更具有可移植性
(2)用法关键是2个sigaction指针
(3)sigaction可以一次得到(单独)设置新捕获函数和获取旧的捕获函数(要获取哪一个捕获函数设另一个为NULL)

8.alarm函数
(1)内核以API形式提供的闹钟
(2)编程实战

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

void func(int sig)
{
        if(sig == SIGALRM)
        {
                printf("alarm happend\n");
        }
}

int main(void)
{
        unsigned int ret = -1;
        struct sigaction act = {0};

        act.sa_handler = func;

        //int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);函数原型
        sigaction(SIGALRM,&act,NULL);
        //signal(SIGALRM,func);//可以替换sigaction
        ret = alarm(5);//第一次调用alarm返回值是0
        printf("1st ret = %d\n",ret);
        sleep(3);

        ret = alarm(5);//返回值是2但是本次alarm会重新定5s
        printf("2st ret = %d\n",ret);
        sleep(1);

        ret = alarm(5);//返回值是4依然重新定时5s
        printf("3st ret = %d\n",ret);

        while(1);
        return 0;
}

9.pause函数
(1)内核挂起
(2)作用就是让当前进程暂停运行,交出CPU给其他进程去执行,当当前进程进入pause状态后当前进程表象为被卡住、阻塞住,要退出pause状态当前进程需要被信号唤醒。

10.使用alarm和pause来模拟sleep

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

void func(int sig)
{

}

void mysleep(unsigned int sec)
{
        struct sigaction act = {0};
        act.sa_handler = func;
        sigaction(SIGALRM,&act,NULL);

        alarm(sec);
        pause();
}

int main(void)
{
        printf("before mysleep\n");
        mysleep(3);
        printf("after mysleep\n");
        return 0;
}