zoukankan      html  css  js  c++  java
  • 信号

    信号概念

    信号机制

    A给B发送信号, B收到信号之前执行自己的代码, 收到信号后, 不管执行到程序的什么位置, 都要暂停运行, 去处理信号, 处理完毕再继续执行, 与硬件中断类似——异步模式. 但信号是软件层面上实现的中断, 早期常被称为“软中断”

    信号的特质: 由于信号是通过软件方法实现, 其实现手段导致信号有很强的延时性. 但对于用户来说, 这个延迟时间非常短, 不易察觉

    每个进程收到的所有信号,都是由内核负责发送的,内核处理。

    与信号相关的事件和状态

    信号的状态: (1) 产生; (2) 未决状态, 产生和递达之间的状态。主要由于阻塞(屏蔽)导致该状态; (3) 递达, 递送并且到达进程

    信号处理方式: (1) 执行默认动作; (2) 忽略(丢弃); (3) 捕捉(调用户处理函数)

    Linux内核的进程控制块PCB是一个结构体, task_struct除了包含进程id, 状态, 工作目录, 用户id, 组id, 文件描述符表, 还包含了信号相关的信息, 主要指阻塞信号集和未决信号集

    阻塞信号集, 未决信号集

    阻塞信号集(信号屏蔽字): 将某些信号加入集合, 对他们设置屏蔽, 当屏蔽x信号后, 再收到该信号, 该信号的处理将推后(解除屏蔽后)

    未决信号集:

    1. 信号产生, 未决信号集中描述该信号的位立刻翻转为1, 表信号处于未决状态. 当信号被处理对应位翻转回为0. 这一时刻往往非常短暂
    2. 信号产生后由于某些原因(主要是阻塞)不能抵达. 这类信号的集合称之为未决信号集. 在屏蔽解除前, 信号一直处于未决状态

    信号4要素

    每个信号也有其必备4要素, 分别是: (1)编号 (2)名称 (3)事件 (4)默认处理动作

    默认动作:
      Term:终止进程
      Ign: 忽略信号(默认即时对该种信号忽略操作)
      Core: 终止进程, 生成Core文件(查验进程死亡原因, 用于gdb调试)
      Stop: 停止(暂停)进程
      Cont: 继续运行进程

    SIGKILL和19SIGSTOP信号, 不允许忽略和捕捉, 只能执行默认动作, 甚至不能将其设置为阻塞

    另外需清楚, 只有每个信号所对应的事件发生了, 该信号才会被递送(但不一定递达), 不应乱发信号

    基础API

    kill

    int kill(pid_t pid, int sig);
    发送信号给指定进程,
    参数: sig建议写宏的名字

    raise

    int raise(int sig);
    给自己发送异常终止信号
    没有参数返回值, 永远不会调用失败

    abort

    void abort(void);
    该函数无返回

    alarm

    unsigned int alarm(unsigned int seconds);
    设定定时器(每个进程只有一个定时器), 使用的是自然定时法, 时间运行不受当前进程的影响

    参数: 秒, 当时间到达之后, 函数发出一个信号SIGALRM, alarm(0)0表示取消闹钟设置, 返回0或剩余的秒数, 无失败

    返回值: 上一个定时器还有多长时间发送信号

    getitimer与setitimer

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

    int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
    定时器, 实现周期性定时
    参数:
      which: 使用哪种定时器, 有三种定时器, 不同定时器的信号不同
        自然定时: ITIMER_REAL: 发送4号SIGLARM; 计算自然时间
        虚拟空间计时(用户空间): ITIMER_VIRTUAL 发送26号SIGVTALRM; 只计算进程占用cpu的时间
        运行时计时(用户+内核): ITIMER_PROF, 发送27号SIGPROF; 计算占用cpu及执行系统调用的时间
      old_value: 传出参数, 上一次设置定时器信息, 一般设置为NULL

    struct itimerval {
       struct timeval it_interval; // 定时周期
       struct timeval it_value;    // 第一次触发定时器的时间
    };
    
    struct timeval {			   // 两个值是相加的关系, 两个变量都需赋值, 否则是垃圾值
       time_t      tv_sec;         /* seconds */
       suseconds_t tv_usec;        /* microseconds */
    };
    

    示例程序

    kill用法

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <signal.h>
    
    int main(int argc, const char *argv[]) {
        pid_t pid = fork();
        if (pid > 0) {
            while (1) {
                printf("parent process, %d
    ", getpid()); 
                sleep(1);
            }
        }
        // child process
        // 杀死父进程
        else if (pid == 0) {
            sleep(2);
            kill(getppid(), SIGKILL);
        }
    
        return 0;
    }
    

    abort用法

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <signal.h>
    #include <sys/wait.h>
    
    int main(int argc, const char *argv[]) {
        pid_t pid = fork();
        if (pid > 0) {
            // 父进程, 回收子进程资源
            int s;
            pid_t wpid = wait(&s);
            printf("child died pid = %d
    ", wpid);
            if (WIFSIGNALED(s)) {
                printf("die by signal: %d 
    ", WTERMSIG(s));
            }
        }
        else if (pid == 0) {
            // 自己给自己发送信号
            //raise(SIGINT);
            while (1) {
                abort();
            }
        }
    
        return 0;
    }
    
    /*
    child died pid = 12779
    die by signal: 6 
    */
    

    alarm用法

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    
    int main(int argc, const char *argv[]) {
        int ret = alarm(5);
        printf("ret = %d
    ", ret);
    
        sleep(2);
        // 重新设置定时器
        ret = alarm(2);
        printf("ret = %d
    ", ret);
    
        while (1) {
            printf("Hello World
    ");
            sleep(1);
        }
    
        return 0;
    }
    

    测试一秒钟程序能数多少数字

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    
    int main(int argc, const char *argv[]) {
        // 设置定时器
        alarm(1);
        int i = 0;
        while (1) {
            printf("%d
    ", i++);
        }
        return 0;
    }
    /*
    timer ./a.out 查看程序执行时间
    real = 用户 + 内核 + 损耗
    */
    

    setitimer使用

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <sys/time.h>
    #include <signal.h>
    
    int main(int argc, const char *argv[]) {
        // 设置定时器
        struct itimerval new_val;
        // 第一次触发的时间
        new_val.it_value.tv_sec = 2;
        new_val.it_value.tv_usec = 0;
    
        // 周期性定时
        new_val.it_interval.tv_sec = 1;
        new_val.it_interval.tv_usec = 0;
    
        // 倒计时2s
        setitimer(ITIMER_REAL, &new_val, NULL);
        while (1) {
            printf("haha
    ");
        }
        
        return 0;
    }
    
  • 相关阅读:
    代码
    怎么创建scrollview
    tcp/Ip http
    游戏道具
    FPS interv
    调整音乐
    插入排序
    冒泡排序
    JSON详解
    设计模式系列(2) 工厂模式之简单工厂模式
  • 原文地址:https://www.cnblogs.com/hesper/p/10738887.html
Copyright © 2011-2022 走看看