20211320LDK《Unix/Linux系统编程第六章》学习笔记

一、知识总结

信号和中断

中断是从I/O设备或协处理器发送到CPU的外部请求,将CPU从正常执行转移到中断处理。信号是发送给进程的请求,将进程从正常执行转移到中断处理

(1)人员中断

人员的每个动作函数都是通过本能或经验实现的,每个中断都分配由一个唯一的ID识别号和一个预先安装的动作函数,人在收到中断请求时“执行”动作函数。

  • 来自硬件的中断
  • 来自其他人的中断
  • 自己造成的中断
  • 不可屏蔽(NMI)
  • 可屏蔽

(2)进程中断

每个进程中断都被转换为一个唯一ID号,发送给进程。Unix/Linux中的进程中断成为信号,编号为1—31.进程也可屏蔽某些类型的信号以推迟处理,必要时可能修改信号动作函数。

  • 来自硬件的中断:定时器、I/O设备等。
  • 来自其他处理器的中断:FFP、DMA、多处理器系统中的其他CPU。
  • 自己造成的中断:除以0、保护错误、INT指令。

(4)进程的陷阱错误

进程可能会自己造成中断,是由被CPU识别为异常的错误引起的(除以0、无效地址、非法指令、越权……),它会陷入操作系统内核,将陷阱原因转换为信号编号发送给自己。

Unix/Linux信号示例

  • Ctrl+C组合键:转换为SIGINT(2)信号,发送给终端,终止当前运行的进程。进程对大多数信号的默认操作是调用内核的kexit(exitValue)函数来终止。
  • 用户可使用nohup a.out命令在后台运行程序,nohup会使sh复刻子进程来执行程序,但子进程会忽略SIGNUP(1)信号。
  • 通过ps -u LTD发现后台进程仍在运行,可使用kill pid (or kill -s 9 pid)杀死进程。执行杀死的进程向pid标识的目标进程发送一个SIGTERM(15)信号,请求它死亡。
  • 如果进程忽略该信号,可能拒绝死亡,可以使用kill -s 9 pid必能杀死。

Unix/Linux中的信号处理

1.信号类型

Unix/Linux支持31种不同的信号,每种信号在signal.h文件中都有定义,每种信号都有一个符号名。

2.信号来源

  • 来自硬件中断的信号
    中断健(Ctrl+C)产生一个SIGINT(2)信号
    间隔定时器:SIGALRM(14)、SIGVTALRM(26)或SIGPROF(27)
    其他硬件错误:总线错误、I/O陷阱等
  • 来自异常的信号
    SIGFPE(8):浮点异常(除以0)
    SIGSEGV(11):段错误
  • 来自其他进程的信号
    可使用kill(pid,sig)系统调用向pid标识的目标进程发送信号。

二、 苏格拉底大挑战

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、 代码实践

#include <stdio.h>  
#include <signal.h>  
  
  
void WrkProcess(int nsig)  
{  
        printf("WrkProcess .I get signal.%d threadid:%d/n",nsig,pthread_self());  
  
  
        int i=0;  
        while(i<5){  
                printf("%d/n",i);  
                sleep(1);  
                i++;  
        }  
}  
  
int main()  
{  
        struct sigaction act,oldact;  
        act.sa_handler  = WrkProcess;  
        act.sa_flags = SA_NODEFER | SA_RESETHAND;     
  
        sigaction(SIGINT,&act,&oldact);  
  
        printf("main threadid:%d/n",pthread_self());  
  
        while(1)sleep(5);  
  
        return 0;  
}  


在这里插入图片描述

四、 问题与解决思路

之前的signal(SIGALARM,function)函数设置的处理函数和本次不一样,那么本次signal函数怎样在不覆盖前次信号处理函数的基础上继续工作呢?

经查找资料,找到了这个。signal的返回值,要么是SIG_ERR,要么是前次信号处理的函数指针,同样在注册函数时,保存上次函数,在函数处理结束前回复原来的值。SIGALARM的默认动作是终止进程。设置SIGALARM信号是为了给调用者一个闹钟,应用的场所一般是在低速设备阻塞时,例如read/write,设置alarm函数可以防止系统长期阻塞,但这里有一个问题就是,在alarm(nsec)和read()之间有一个竞争关系,如果在read()之前调用了alarm()函数,那么read()还是会长期阻塞。解决这个问题可以通过setjmp和longjmp函数来解决,因为setjmp设置的时候返回0,longjmp可以设置不同的返回值,可以将read函数包裹在setjmp = 0里面,这样如果处理函数里面的longjmp跳转了也不会出现上面的问题了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值