LinuxC进程通信-信号学习笔记

本文主要探讨了Linux中进程通信的信号机制,包括中断的基本概念,软件中断即信号的特点。介绍了常用信号如SIGINT、SIGSTOP等,并讲解了信号捕获、发送的方式,如键盘快捷键触发。此外,还涉及了进程休眠、信号集与信号屏蔽的使用,以及通过getitimer函数操作的定时器类型。
摘要由CSDN通过智能技术生成

基本概念:
1.中断
当进程接收到信息后终止当前正在执行的进程,转而去执行其他任务,等其他任务
完成后再放回,这种模式叫做中断模式。中断分为硬中断和软中断
2、信号
是一种软件中断,由操作系统发出,进程接收后会执行相应的操作
3、常见的信号
kill -l 显示出所有信号
SIGINT(2) 终端中断符信号

4、不可靠信号和可靠信号
    建立在早期的信号处理机制上的信号(1-31),是不可靠信号
    不支持排队,可能会丢失信号,同一个信号如果连续产生多次,进程可能只处理
    了一次。
    建立在新的信号处理机制上的信号(34~64),是可靠信号
    支持排队,不会丢失的
5、信号来源
    硬件异常:除0,无效的内存访问、未定义的指令、总线错误
    软件异常:一般通过命令、函数产生的信号
6、信号的处理方式
    1、忽略
    2、终止进程
    3、终止并产生库文件
    4、捕获并处理信号
        (在信号来之前,向内核注册一个函数,当信号发生后,系统会自动执行注册函数)

信号捕获:
#include <signal.h>

typedef void (*sighandler_t)(int);
功能:信号处理函数的格式,必须遵循

sighandler_t signal(int signum, sighandler_t handler);
功能:向内核注册一个绑定某个信号的信号处理函数
signum:信号编号
handler:函数指针
    除了直接给函数名外,还可以给以下参数:
        SIG_IGN 忽略
        SIG_DFL 按默认方式处理
返回值:
    之前的信号处理方式  

注意: 
    1、一个函数可以同时绑定多个信号
    2、个别系统通过signal注册的函数只能执行一次,如果想要持续有效,可以在信号处理函数中再注册一次
    3、信号处理完后会返回产生信号的代码持续执行,如果我们捕获并处理了段错误、算术异常信号,可能会
    产生死循环,因此正确地处理段错误、算术异常应该是备份数据并结束进程
    4、子进程会继承父进程的信号处理方式

练习2:测试一下1-31哪些信号不能被捕获处理
    kill函数
    9 19号信号不能被捕获也不能忽略

信号的发送:
键盘:
Ctrl+c
Ctrl+
Ctrl+z 暂停\挂起 命令fg唤醒

错误:
    除0
    非法访问内存
    硬件错误、总线错误
命令:
    kill  -信号  进程号
    killall -信号 进程名
        可以向同名的多个进程发送同一个信号

函数:
    int kill(pid_t pid, int sig);
功能:向指定进程发送指定信号
pid:进程号
sig:信号编号

int raise(int sig);
功能:向进程自己发送信号sig

void abort(void);
功能:向自己发送SIGABRT信号

unsigned int alarm(unsigned int seconds);
功能:让内核在seconds秒后向调用者发送SIGALRM信号
返回值:上一次alarm设置的剩余秒数
注意: 如果再次调用时,会覆盖之前的设置,按照新的设置时,因此不会产生多次闹钟信号

进程休眠信号:
int pause(void);
功能:让调用者进入休眠状态,直到进程遇到信号
返回值:要不一直休眠不返回,要么返回-1
相当于没有时间限制的sleep

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:获取旧的信号屏蔽集 输出型参数 不接可以给NULL

定时器:
#include <sys/time.h>
int getitimer(int which, struct itimerval *curr_value);
功能: 获取当前的定时方案
which:选择一个计时器
ITIMER_REAL 真实计时器 程序总的执行时间 SIGALRM
ITIMER_VIRTUAL 虚拟计时器 用户态的执行时间 SIGALRM
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;        //微秒
    };
    注意:如果tv_usec的值超过一秒以上,方案会失效
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值