ECF
来源:互联网 发布:淘宝app 设备管理 编辑:程序博客网 时间:2024/04/28 22:48
Exceptional Control Flow(异常控制流)
处理器检测到异常时,通过异常表调用异常处理程序进行处理。
可以通过
- 跳转和分支
- 调用和返回
改变控制流。但是当系统状态发生变化时,需要ECF进行处理。
- 硬件层:异常(图8-1)
处理器状态发生变化(event)时,通过异常表调用相应的异常处理程序(运行在内核模式下)。- 中断:异步异常。由处理器外面发生的事件引起的,例如计时器中断和 I/O 中断。返回后执行下一条指令。
- 陷阱:同步异常。向用户提供系统调用(用户程序和内核的接口)调用相应的内核程序。返回后执行下一条指令。
在 x86-64 系统中,每个系统调用都有一个唯一的 ID。参数通过通用寄存器传递。使用syscall指令进行系统调用。 - 故障:同步异常。程序发生错误时,处理器将控制交给故障处理程序。如果处理成功,重新执行该指令;否则终止该指令所在程序。
- 终止:同步异常。由不可恢复的错误造成,直接退出当前的程序。
操作系统层:进程切换
进程:- 逻辑控制流:
上下文
切换的内核机制让每个程序都感觉自己在独占处理器
进程切换:内核通过调度器(代码)调度进程,进程轮流执行逻辑流的一部分
并发:伪并行执行(例如进程A只在进程C执行的间隙执行,则称进程AC并发)
并行:使用多个 CPU 同时执行 私有地址空间:
通过虚拟内存机制让每个程序都感觉自己在独占内存进程状态:
运行:正在或者等待被执行
停止:执行被挂起,在进一步通知前不会计划执行
终止:进程被永久停止- 进程组:
每个进程只属于1个进程组
父子进程同属1个进程组
- 逻辑控制流:
getpgrp() //返回当前进程所在进程组IDsetpgid(pid_t pid,pid_t pgid) //设置一个进程的进程组CP528
- 进程控制:
1.(系统调用的)错误处理:使用错误处理包装函数简化代码
pid_t Fork(void)//包装函数{ pid_t pid; //Unix的系统级函数遇到错误时会返回-1 if ( (pid = fork()) < 0 ) unix_error("Fork error"); return pid;}void unix_error(char *msg) //错误处理函数 { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0);}
2.获取进程信息:
- pid_t getpid(void) :返回当前进程的 PID(进程ID)
- pid_t getppid(void) : 返回当前进程的父进程的 PID
3.创建进程:
父进程通过fork函数(返回该进程的子进程PID,返回2次)调用子进程(父进程的副本)
在父进程中;在新创建的子进程中,fork函数返回0
子进程共享父进程打开的文件
父子进程是并发运行的独立进程(有独立的地址空间)
execve函数在当前进程中加载并运行1个新程序(程序运行在进程的上下文中)。注意新程序的PID不变,覆盖当前的地址空间,继承调用函数时已打开的文件。
4.子进程回收
当进程终止后,内核会中断常规执行并通过信号通知。只有被其父进程回收时,系统才会清除该进程。
如果父进程在回收子进程之前被终止,内核通过init进程回收
应用层:
- 信号
一种异步的通知机制,用来提醒进程一个事件已经发生。
1.当内核检测到进程发生某种事件,内核将对应的信号发送给该进程:
2.进程调用kill函数,显式要求内核发送信号给该进程。
发送信号:内核更新目的进程上下文的某个状态
- 信号
/* /bin/kill程序发送信号 */linux> /bin/kill -9 24818//发送信号9给进程24818linux> /bin/kill -9 24818//发送信号9给进程组24818的每个进程
/* kill函数发送信号 */int kill(pid_t pid,int sig);//CP530
键盘发送信号
Ctrl+C:内核终止前台作业
Ctrl+Z:内核挂起前台作业
接收信号:操作系统中断了进程正常的控制流程。
每个信号类型都有默认行为:
- 忽略这个信号
- 终止进程
- 捕获信号,执行信号处理器
进程可以通过signal函数修改默认行为。
//函数指针typedef void(*sighandler_t)(int);//设置信号处理函数sighandler_t *signal(int signum, handler_t *handler);
void sigint_handler(int sig) // SIGINT 处理器{ printf("不能通过ctrl+c关闭\n"); exit(0);}int main(){ // 接收到由于Ctrl+C发出的信号,调用sigint_handler作为信号处理函数 if (signal(SIGINT, sigint_handler) == SIG_ERR) unix_error("signal error"); // 等待接收信号 pause(); return 0;}
阻塞信号:
- 隐式阻塞机制:当信号处理程序正在运行时,内核默认阻塞同一类型的信号
- 显式阻塞机制:使用 sigprocmask 函数以及其他辅助函数CP533
信号处理器也可以被其他的信号处理器中断。
等待状态:信号已被发送但是未被接收。同类型的信号至多只会有一个待处理信号。
信号处理器和主程序并行且共享相同的全局数据结构,尤其要注意因为并行访问可能导致的数据损坏的问题。基本的指南:
- 规则 1
信号处理器越简单越好 - 规则 2
信号处理器中只调用异步且信号安全(async-signal-safe)的函数 - 规则 3
在进入和退出的时候保存和恢复 errno
这样信号处理器就不会覆盖原有的 errno 值 - 规则 4
临时阻塞所有的信号以保证对于共享数据结构的访问
防止可能出现的数据损坏 - 规则 5:
用 volatile 关键字声明全局变量
编译器就不会把它们保存在寄存器中,保证一致性 规则 6
用 volatile sig_atomic_t 来声明全局标识符(flag)
这样可以防止出现访问异常非本地跳转:从一个函数跳转到另一个函数中
本地跳转:在一个程序中通过 goto 语句进行流程跳转
//保存当前程序的堆栈上下文环境/*仅在调用 setjmp 的函数内有效,如果调用 setjmp 的函数返回则失效。*/int setjmp(jmp_buf env);/*恢复由 setjmp 保存的程序堆栈上下文,即程序从调用 setjmp 处重新开始执行*/int longjmp(jmp_buf env,int retval);
setjmp 函数被调用1次,返回2次。
1. 第1次调用setjmp 函数返回0;
2. 调用longjmp函数返回retval
允许从深层嵌套中避开调用栈直接返回。
(C++的try语句属于该函数更高级的版本,catch语句类似于setjmp 函数,throw语句类似于longjmp函数)
- ECF
- ecf笔记
- Virgo整合ECF
- 异常控制流(ECF)机制--简介
- 用Eclipse RCP & ECF 实现 Google Talk客户端
- [Read only - use Ctrl-Ecf for console write access.]
- Eclipse-ECF 感受奇妙的协同编程之旅
- OSGI.基于ECF的分布式服务开发指南
- 利用Unix-ECF实现睡眠排序(SleepSort)和闹钟(Alarm)
- eclipse插件开发[用Eclipse RCP & ECF 实现 Google Talk客户端]
- 虚数的意义
- 微服务开发的入门级框架Spring Boot详解(一)
- 字符串分割(C++)
- idea,解决maven报红问题
- iotop 移植linux/arm
- ECF
- 第一行代码第二版 使用百度定位
- 浅析人脸检测之Haar分类器方法:Haar特征、积分图、 AdaBoost 、级联
- Trip(trip) 【NOIP2017模拟8.8A组】
- JPA学习笔记(11)——映射双向多对多关联关系
- Python错误: SyntaxError: Non-ASCII character
- 欢迎使用CSDN-markdown编辑器
- HDU 6114 Chess【组合数学】
- php函数serialize()与unserialize()