uc笔记08---信号处理,signal,子进程的信号处理

1.    基本概念
    1)中断
    中止(注意不是终止)当前正在执行的程序,转而执行其它任务。

    硬件中断:来自硬件设备的中断。
    软件中断:来自其它程序的中断。

    2)信号是一种软件中断
    信号提供了一种以异步方式执行任务的机制。

    3)常见信号

        SIGHUP(1):连接断开信号
        如果终端接口检测一个连接断开,
        则将此信号发送给与该终端相关的控制进程(会话首进程)。
        默认动作:终止。

        SIGINT(2):终端中断符信号
        用户按中断键(Ctrl+C),产生此信号,
        并送至前台进程组的所有进程。
        默认动作:终止。
        (相当于:kill -2 20505)

        SIGQUIT(3):终端退出符信号
        用户按退出键(Ctrl+\),产生此信号,
        并送至前台进程组的所有进程。
        默认动作:终止+core。
        (core 相当于一个快照,用于时候诊断)

        SIGILL(4):非法硬件指令信号
        进程执行了一条非法硬件指令。
        默认动作:终止 + core。

        SIGTRAP(5):硬件故障信号
        指示一个实现定义的硬件故障。常用于调试。
        默认动作:终止 + core。

        SIGABRT(6):异常终止信号
        调用abort函数,产生此信号。
        默认动作:终止 + core。

        SIGBUS(7):总线错误信号
        指示一个实现定义的硬件故障。常用于内存故障。
        默认动作:终止 + core。

        SIGFPE(8):算术异常信号
        表示一个算术运算异常,例如除以 0、浮点溢出等。
        默认动作:终止 + core。

        SIGKILL(9):终止信号
        不能被捕获或忽略,常用于杀死进程。
        默认动作:终止。

        SIGUSR1(10):用户定义信号
        用户定义信号,用于应用程序。
        默认动作:终止。

        SIGSEGV(11):段错误信号
        试图访问未分配的内存,或向没有写权限的内存写入数据。
        默认动作:终止 + core。

        SIGUSR2(12):用户定义信号
        用户定义信号,用于应用程序。
        默认动作:终止。

        SIGPIPE(13):管道异常信号
        写管道时读进程已终止,
        或写 SOCK_STREAM 类型套接字时连接已断开,均产生此信号。
        默认动作:终止。

        SIGALRM(14):闹钟信号
        以 alarm 函数设置的计时器到期,
        或以 setitimer 函数设置的间隔时间到期,均产生此信号。
        默认动作:终止。

        SIGTERM(15):终止信号
        由 kill 命令发送的系统默认终止信号。
        默认动作:终止。
        (和 9 的区别是:15 可以被忽略)

        SIGSTKFLT(16):数协器栈故障信号
        表示数学协处理器发生栈故障。
        默认动作:终止。

        SIGCHLD(17):子进程状态改变信号
        在一个进程终止或停止时,将此信号发送给其父进程。
        默认动作:忽略。

        SIGCONT(18):使停止的进程继续
        向处于停止状态的进程发送此信号,令其继续运行。
        默认动作:继续/忽略。

        SIGSTOP(19):停止信号
        不能被捕获或忽略。停止一个进程。
        默认动作:停止进程。

        SIGTSTP(20):终端停止符信号。
        用户按停止键(Ctrl+Z),产生此信号,
        并送至前台进程组的所有进程。
        默认动作:停止进程。

        SIGTTIN(21):后台读控制终端信号
        后台进程组中的进程试图读其控制终端,产生此信号。
        默认动作:停止。

        SIGTTOU(22):后台写控制终端信号
        后台进程组中的进程试图写其控制终端,产生此信号。
        默认动作:停止。

        SIGURG(23):紧急情况信号
        有紧急情况发生,或从网络上接收到带外数据,产生此信号。
        默认动作:忽略。

        SIGXCPU(24):超过 CPU 限制信号
        进程超过了其软 CPU 时间限制,产生此信号。
        默认动作:终止 + core。

        SIGXFSZ(25):超过文件长度限制信号
        进程超过了其软文件长度限制,产生此信号。
        默认动作:终止 + core。

        SIGVTALRM(26):虚拟闹钟信号
        以 setitimer 函数设置的虚拟间隔时间到期,产生此信号。
        默认动作:终止。

        SIGPROF(27):虚拟梗概闹钟信号
        以 setitimer 函数设置的虚拟梗概统计间隔时间到期,产生此信号。
        默认动作:终止。

        SIGWINCH(28):终端窗口大小改变信号
        以 ioctl 函数更改窗口大小,产生此信号。
        默认动作:忽略。

        SIGIO(29):异步 I/O 信号
        指示一个异步 I/O 事件。
        默认动作:终止。

        SIGPWR(30):电源失效信号
        电源失效,产生此信号。
        默认动作:终止。

        SIGSYS(31):非法系统调用异常。
        指示一个无效的系统调用。
        默认动作:终止 + core。

    4)不可靠信号(非实时信号)
    a. 那些建立在早期机制上的信号被称为“不可靠信号”。
        小于 SIGRTMIN(34) 的信号都是不可靠信号。
    b. 不支持排队,可能会丢失。同一个信号产生多次,进程可能只收到一次该信号。
    c. 进程每次处理完这些信号后,对相应信号的响应被自动恢复为默认动作,
        除非显示地通过 signal 函数重新设置一次信号处理程序。

    5)可靠信号(实时信号)
    a. 位于 [SIGRTMIN(34), SIGRTMAX(64)] 区间的信号都是可靠信号。
    b. 支持排队,不会丢失。
    c. 无论可靠信号还是不可靠信号,都可以通过 sigqueue/sigaction 函数发送/安装,
        以获得比其早期版本 kill/signal 函数更可靠的使用效果。

    6)信号的来源
    a. 硬件异常:除 0、无效内存访问等。
        这些异常通常被硬件(驱动)检测到,并通知系统内核。
        系统内核再向引发这些异常的进程递送相应的信号。
    b. 软件异常:
        通过 kill/raise/alarm/setitimer/sigqueue 函数产生的信号。

    7)信号处理
    a. 忽略。
    b. 终止进程。
    c. 终止进程同时产生 core 文件。
    d. 捕获并处理。
        当信号发生时,内核会调用一个事先注册好的用户函数(信号处理函数)。

    范例:loop.c
        #include <stdio.h>
        int main (void) {
            printf ("%u进程:我在运行,按<Ctrl+C>或<Ctrl+\\>终止...\n",
                getpid ());
            for (;;);            // 死循环,用于手动终止
            return 0;
        }
    运行测试:
    # a.out
    按中断键(Ctrl+C),发送 SIGINT(2) 终端中断符信号。

    # a.out
    按退出键(Ctrl+\),发送 SIGQUIT(3) 终端退出符信号。

2.    signal

    #include <signal.h>
    typedef void (*sighandler_t) (int);
    sighandler_t signal (int signum,
            sighandler_t handler);

    signum  - 信号码,也可使用系统预定义的常量宏,如 SIGINT 等。
    handler - 信号处理函数指针或以下常量:
                SIG_IGN: 忽略该信号;
                SIG_DFL: 默认处理。

    成功返回原来的信号处理函数指针或 SIG_IGN/SIG_DFL 常量,
    失败返回 SIG_ERR。

    1)在某些 Unix 系统上,通过 signal 函数注册的信号处理函数只一次有效,
    即内核每次调用信号处理函数前,会将对该信号的处理自动恢复为默认方式。
    为了获得持久有效的信号处理,可以在信号处理函数中再次调用 signal 函数,重新注册一次。

    例如:
    void sigint (int signum) {
        . . .
        signal (SIGINT, sigint);
    }
    int main (void) {
        . . .
        signal (SIGINT, sigint);
        . . .
    }

    2)SIGKILL/SIGSTOP 信号不能被忽略,也不能被捕获。
    3)普通用户只能给自己的进程发送信号,root用户可以给任何进程发送信号。

    范例:signal.c(自定义信号处理方式)
        #include <stdio.h>
        #include <signal.h>
        void sigint (int signum) {
            printf ("%u进程:收到SIGINT信号!\n", getpid ());
        //    signal (SIGINT, SIG_DFL);
        //    signal (SIGINT, sigint);
        }
        void sigkill (int signum) {
            printf ("%u进程:收到SIGKILL信号!\n", getpid ());
        }
        int main (void) {
            /*
            if (signal (SIGINT, SIG_IGN) == SIG_ERR) {
                perror ("signal");
                return -1;
            }
            */
            // 截获 <Ctrl+C>,自定义处理方式
            // 在新版 linux 系统里,该信号的处理不会自动恢复为默认方式,也就是信号回调;
            if (signal (SIGINT, sigint) == SIG_ERR) {
                perror ("signal");
                return -1;
            }
            /*
            if (signal (SIGKILL, SIG_IGN) == SIG_ERR) {    // 报错,SIGKILL 不能被忽略
                perror ("signal");
                return -1;
            }
            if (signal (SIGKILL, sigkill) == SIG_ERR) {    // 报错,SIGKILL 不能被捕获
                perror ("signal");
                return -1;
            }
            */
            printf (&#
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值