Linux的信号处理

基本概念:

    1、中断

        当程序接收到信息后终止了当前正在执行的程序,转而执行其他的任务,等其他任务执行完成后可能再返回继续执行,这种执行模式称为中断执行

        分为硬件中断和软件中断

        硬件中断由外设硬件产生的中断,例如键盘、鼠标都可以产生,可以屏蔽

        软件中断是程序执行了中断指令后产生的中断

    2、信号

        信号是一种软件中断,是由操作系统发出的中断信号,被程序就收后执行相应的操作

    3、常见的信号

        kill -l 显示所有信号

        SIGINT(2)   Ctrl+c  终止

        SIGQUIT(3)  Ctrl+\  终止+core(内存映像 内存崩溃时)

        SIGFPE(8)   除0\溢出 终止+core(内存映像 内存崩溃时)

        SIGKILL(9)  用于杀死进程    终止

        SIGSEGV(11) 非法访问内存    终止

    4、不可靠信号和可靠信号

        建立在早期的信号处理机制上的信号(1~31),称为不可靠信号

            不支持排队机制,可能会丢失信号,如果同一个信号连续发送多次,进程可能只接收到了一次

        建立在新的信号处理机制上的信号(34~64),称为可靠信号

            支持排队机制,如果信号连续发送,也不会丢失

    5、信号的来源

        硬件异常:除0,非法访问内存,使用了未定义的指令,总线错误等

        软件异常:通过一些命令、函数产生异常

    6、信号的处理

        1、忽略

        2、终止进程

        3、终止进程+产生core文件

        4、捕获并处理信号(在信号发出前,向内核注册一个信号处理函数,绑定该信号与信号处理函数,当信号发出后,会处理信号处理函数)

信号捕获和注册

    typedef void (*sighandler_t)(int);

    注意:信号处理函数的格式

        参数int表示是导致执行该函数的信号的ID

    sighadler_t signal(int signum,sighadler_t headler)

    功能:向内核提出绑定一个信号处理函数

    signal:信号编号

    headler:信号处理函数的函数名

        还可以写成:

        SIG_IGN 忽略处理

        SIG_GFL 按默认方式处理

    返回值:返回绑定之前的信号处理函数指针,一般用于记录还原

    注意:有个别操作系统通过signal注册的信号只能执行一次信号处理函数,如果想要持续有效,可以在信号处理函数中再重新signal注册一次。

    注意:虽然有些信号可以捕获,但是产生该信号的错误原因依旧还在(段错误、除0),如果信号处理函数执行完后不终止进程,就会返回到产生错误的位置,导致死循环,正确操作是保存数据后,终止程序

    信号发出的方式:

        键盘:

            Ctrl+c

            Ctrl+\

            Ctrl+z  暂停\挂起 fg命令恢复最后暂停的进程

        错误:

            非法访问内存

            除0

            硬件的故障、总线错误

            (捕获后要及时终止进程)

        命令:

            kill -信号id 进程号

            killall -信号id 进程名

                发送信号给所有名字为同名的进程

        函数:

        int kill(pid_t pid, int sig);

        功能:向指定的进程发送信号

        pid:进程号

        sig:信号

       

        int rasie(int sig);

        功能:给进程自己发送信号

        void abort(void);

        功能:给进程自己发送SIGABRT(6)信号

        unsigned int alarm(unsigned int seconds);

        功能:让内核在seconds秒后想进程自己发送SIGALRM(14)信号

        返回值:上一次调用后,闹钟剩余的秒数

        注意:如果重复调用该函数,只会覆盖之前的设置时间,而不会产生多次闹钟信号

进程休眠与信号:

    int pause(void);

    功能:让调用者进程进入休眠态,直到遇到信号后就会唤醒

    返回值:要么一直不返回,要么信号来了返回-1

    unsigned int sleep(unsigned int seconds);

    功能:让调用者进程进入休眠态指定秒数,当遇到信号时会提前返回

    返回值:还在休眠中不返回,唤醒后返回剩余休眠秒数

信号集与信号屏蔽(阻塞):

    信号集:是一种数据类型,定义出来的变量可以存储表示多个信号

        sigset_t 128位的二进制数

        用每一个二进制位来表示某种信号有无

        相关函数:

        int sigemptyset(sigset_t *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);

        功能:测试查看信号集中是否有某个信号

        返回值:

            0   不存在

            1   存在

            -1  信号非法

    信号屏蔽:

        当程序执行一些特殊操作时是不合适处理信号的,此时可以让内核先屏蔽信号处理,等特殊操作完成后再继续处理信号

        当信号产生时,内核会在该进程中的信号维护表中为该进程标记此信号,一旦完成标记进程就开始响应信号,次过程称为递送

        从信号产生到完成递送过程有一个时间间隔,处于这个时间间隔的信号的状态叫未决

        信号屏蔽就是让信号处于未决状态,暂停递送,当屏蔽解除时再继续进行递送

        一般每个进程都有一个信号集用于存储要屏蔽的信号,称为信号屏蔽集

       

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

        功能:设置信号屏蔽集

        how:信号屏蔽的方式

            SIG_BLOCK

                把set中信号添加到信号屏蔽集中

            SIG_UNBLOCK

                从信号屏蔽集中删除set中的信号

            SIG_SETMASK

                把信号屏蔽集的信号全部替换成set中的信号

        set:准备设置的信号集

        oldset:获取旧的信号屏蔽集

附带信息的高级信号处理:

    int sigaction(int signum, const struct sigaction *act,

                 struct sigaction *oldact);

    功能:向内核处理一个信号处理函数,相当于signal的升级版

    signum:要捕获的信号

    act:

        struct sigaction {

            void (*sa_handler)(int);//不附带数据的信号处理函数

            void (*sa_sigaction)(int, siginfo_t *, void *);//附带附加数据的信号处理函数

            sigset_t   sa_mask; //信号屏蔽集

            //在该函数执行时,默认会屏蔽当前信号,如果想要屏蔽其他信号,可以向sa_mask中增加信号

            int  sa_flags;  //绑定信号的标志位

                SA_SIGINFO  使用第二个函数指针进行绑定

                SA_NODEFER  在信号绑定过程中不要屏蔽该信号

                SA_RESETHAND 在该信号处理方式执行完后,还原回默认的处理方式

                SA_RESTART  系统调用一旦被该绑定的信号打断后可以自动重启系统调用

            void (*sa_restorer)(void); //保留项

        };

int sigqueue(pid_t pid, int sig, const union sigval value);

    功能:向指定的进程发送附带有数据的信号

    pid:进程号

    sig:信号ID

    value:要附带的数据

     union sigval {

        int   sival_int;    //整数

        void *sival_ptr;    //指针

    };

    注意:通过这样附带信息的操作,可以让不同的进程进行数据通信

定时器:

    int getitimer(int which, struct itimerval *curr_value);

    功能:获取当前定时方案

    which:选择计时器

        ITIMER_REAL     真实计时器  程序的总运行时间SIGALRM

        ITIMER_VIRTUAL  虚拟计时器  用户态的运行时间SIGVTALRM

        ITIMER_PROF     实际计时器  用户态+内核态的运行时间SIGPROF

        真实计时器 = 实际计时器+切换时间+休眠时间

    int setitimer(int which, const struct itimerval *new_value,

    struct itimerval *old_value);

    功能:设置新的定时方案

    struct itimerval {

        struct timeval it_interval; //  每次计时器产生信号的时间间隔

        struct timeval it_value;    //  第一次信号产生的时间

    };

    struct timeval {

        time_t      tv_sec;         //  秒

        suseconds_t tv_usec;        //  微秒

    };

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值