- 浏览: 508776 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
jkxydp:
算法运行的结果根本就不对。
BM算法. -
soarwindzhang:
感谢博主的分享,我今天看了您的UFSET非递归的路径压缩时感觉 ...
并查集 -
zhangning290:
楼主好像只考虑了坏字符规则,。没有考虑好后缀
BM算法. -
lsm0622:
文字描述有错误 误导新学者
求有向图的强连通分量(scc):Tarjan算法 -
knightchen:
博主,你太强了!这篇文章对我学习C++多线程很有帮助!谢谢
并发学习之一_windows下ZThread在CodeBlocks上的安装与配置
异常控制流(ECF)
1,这里异常指允许程序进行非本地跳转(违反通常的调用/返回栈规则的跳转)。
2,异常处理完成后,发生三种情况:
(1)执行当前指令Icurr
(2)执行下一条指令Inext
(3)处理程序终止被中断的程序。
3,每种异常=》惟一的非服整数的异常号。
系统启动时,操作系统分配和初始化一张称为异常表的跳转表,使得表目k包含异常k的处理程序的地址。
异常表的起始地址放在叫做异常表基址寄存器的特殊CPU寄存器里。
4,异常的类别:
(1)中断(interrupt):来自处理器外部的I/O设备的信号的结果。
(2)陷阱(trap):有意的异常。最重要的用途:提供用户程序和内核的接口:系统调用。
(3)故障(fault):由错误情况引起,可能被故障处理程序修正。经典示例:缺页异常。
(4)终止(abort):不可恢复的致命的错误。
5,进程的经典定义:一个执行的程序的实例。每个程序都运行在某个进程的上下文。
上下文是由程序正确运行所需的状态组成的。
这个状态包括:存放在存储器中的代码和数据,栈,通用目的寄存器的内容,程序计数器,环境变量,打开文件描述符的集合。
进程提供给应用程序的关键抽象:
一个独立的逻辑控制流。
一个私有的地址空间。
6,寄存器的一个模式位:
用户模式:限制一个应用可以执行的指令和可以访问的地址空间范围。
内核模式:可以执行指令集合中的任何指令,访问系统中任何存储器位置。
7,中断也可能引发上下文切换:如周期性定时器中断的机制。(1到10毫秒)
每次定时器中断,内核就判定当前进程已经运行了足够长的时间了,并切换到一个新的进程。
8,子进程得到与父进程用户级虚拟地址空间相同的一份拷贝,包括文本,数据和bss段,堆以及用户栈。
还获得父进程任何打开的文件描述符的拷贝。子进程可以读写父进程打开的任何文件。
注:父进程和子进程是独立的进程,它们每个都有自己的私有地址空间。
9,关于fork的使用:
程序1:
输出结果:
parent: x=0
child : x=2
修改下main:
输出结果:
child : x=2
parent: x=1
parent: x=0
(2)
输出结果:
hello.
hello
输出结果:
hello.
hello.
hello.
hello.
hello.
hello.
hello.
hello.
10,终止了还未被回收的进程称为僵死进程。
waitpid错误条件:
调用进程没有子进程,返回-1,设置errno为ECHILD
waitpid被一个信号中断,返回-1,设置errno为EINTR
11,使用waitpid函数回首僵死子进程。
按照僵死进程创建的顺序回收。
12,sleep:将一个进程挂起一段时间。
pause:让函数休眠,直到该进程收到一个信号。
execve(char* filename, char* argv[], char* envp[]):在当前进程的上下文中加载并运行一个新进程。
它会覆盖当前进程的地址空间,但并没有创建一个新进程。有相同的PID,并继承了调用execve函数时打开的所有文件描述符。
13,发送信号的原因:
(1)内核检测到一个系统事件。
(2)调用kill函数,显式要求内核发送一个信号给目的进程。
14,内核为每个进程在pending位向量维护者待处理信号集合。
而在blocked位向量维护着被阻塞的信号集合。
15,常见信号:
SIGINT:来自键盘的中断(ctrl+c)
SIGTSTP:来自键盘的暂停信号(ctrl+z)
SIGSTOP:不来自终端的暂停信号。
SIGCHLD:一个子进程暂停或终止。
SIGKILL:杀死进程。
SIGALRM:来自alarm函数的定时器信号
实例代码:
16,unsigned int alarm(unsigned int secs):安排内核在secs秒内发送一个SIGALRM信号给调用进程。
返回:前一次闹钟剩余的秒数,对它的调用将会取消待处理的闹钟。
以前没有设定闹钟,返回0。
实例代码:
17,
typedef void handler_t(int);
handler_t *signal(int signum, handler_t *handler)
三种方法处理信号signum:
如果handler是SIG_IGN,那么忽略类型为signum的信号。
如果handler是SIG_DFL,默认行为。
信号处理程序。
18,非本地跳转。
int setjmp(jmp_buf env);//只调用一次,但返回很多次。
一次是第一次调用setjmp,栈的上下文保存在缓冲区env。
longjmp从env缓冲区中恢复栈的内容,从最近初始化env的setjmp调用返回。
实例代码:
非本地跳转的另一个重要应用:使一个信号处理程序转移到一个特殊的代码位置。
而不是返回到被信号到达中断了的指令的位置。
1,这里异常指允许程序进行非本地跳转(违反通常的调用/返回栈规则的跳转)。
2,异常处理完成后,发生三种情况:
(1)执行当前指令Icurr
(2)执行下一条指令Inext
(3)处理程序终止被中断的程序。
3,每种异常=》惟一的非服整数的异常号。
系统启动时,操作系统分配和初始化一张称为异常表的跳转表,使得表目k包含异常k的处理程序的地址。
异常表的起始地址放在叫做异常表基址寄存器的特殊CPU寄存器里。
4,异常的类别:
(1)中断(interrupt):来自处理器外部的I/O设备的信号的结果。
(2)陷阱(trap):有意的异常。最重要的用途:提供用户程序和内核的接口:系统调用。
(3)故障(fault):由错误情况引起,可能被故障处理程序修正。经典示例:缺页异常。
(4)终止(abort):不可恢复的致命的错误。
5,进程的经典定义:一个执行的程序的实例。每个程序都运行在某个进程的上下文。
上下文是由程序正确运行所需的状态组成的。
这个状态包括:存放在存储器中的代码和数据,栈,通用目的寄存器的内容,程序计数器,环境变量,打开文件描述符的集合。
进程提供给应用程序的关键抽象:
一个独立的逻辑控制流。
一个私有的地址空间。
6,寄存器的一个模式位:
用户模式:限制一个应用可以执行的指令和可以访问的地址空间范围。
内核模式:可以执行指令集合中的任何指令,访问系统中任何存储器位置。
7,中断也可能引发上下文切换:如周期性定时器中断的机制。(1到10毫秒)
每次定时器中断,内核就判定当前进程已经运行了足够长的时间了,并切换到一个新的进程。
8,子进程得到与父进程用户级虚拟地址空间相同的一份拷贝,包括文本,数据和bss段,堆以及用户栈。
还获得父进程任何打开的文件描述符的拷贝。子进程可以读写父进程打开的任何文件。
注:父进程和子进程是独立的进程,它们每个都有自己的私有地址空间。
9,关于fork的使用:
程序1:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <errno.h> #include <time.h> #include <sys/wait.h> void unix_error(char *msg) /* unix-style error */ { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid; } int main() { pid_t pid; int x = 1; pid = Fork(); //line:ecf:forkreturn if (pid == 0) { /* Child */ printf("child : x=%d\n", ++x); //line:ecf:childprint exit(0); } /* Parent */ printf("parent: x=%d\n", --x); //line:ecf:parentprint exit(0); }
输出结果:
parent: x=0
child : x=2
修改下main:
int main() { pid_t pid; int x = 1; pid = Fork(); //line:ecf:forkreturn if (pid == 0) printf("child : x=%d\n", ++x); //line:ecf:childprint /* Parent */ printf("parent: x=%d\n", --x); //line:ecf:parentprint exit(0); }
输出结果:
child : x=2
parent: x=1
parent: x=0
(2)
int main() { Fork(); printf("hello.\n"); exit(0); }
输出结果:
hello.
hello
int main() { Fork(); Fork(); Fork(); printf("hello.\n"); exit(0); }
输出结果:
hello.
hello.
hello.
hello.
hello.
hello.
hello.
hello.
10,终止了还未被回收的进程称为僵死进程。
waitpid错误条件:
调用进程没有子进程,返回-1,设置errno为ECHILD
waitpid被一个信号中断,返回-1,设置errno为EINTR
11,使用waitpid函数回首僵死子进程。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <errno.h> #include <sys/wait.h> #define N 4 void unix_error(char *msg) /* unix-style error */ { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid; } int main() { int status,i; pid_t pid; for (i = 0; i < N; i++) if((pid=Fork()) == 0) exit(100+i); //-1,挂起调用进程的执行 ,直到等待集合中的一个子进程终止。 while((pid=waitpid(-1, &status, 0)) > 0) { if(WIFEXITED(status)) printf("child %d terminated normally with exit status=%d\n", pid,WEXITSTATUS(status)); else printf("child %d teminated abnormally\n", pid); } if(errno != ECHILD) unix_error("waitpid error"); exit(0); }
按照僵死进程创建的顺序回收。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <errno.h> #include <sys/wait.h> #define N 4 void unix_error(char *msg) /* unix-style error */ { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid; } int main() { int status,i; pid_t pid[N],retpid; for (i = 0; i < N; i++) if((pid[i]=Fork()) == 0) exit(100+i); //-1,挂起调用进程的执行 ,直到等待集合中的一个子进程终止。 i=0; while((retpid=waitpid(pid[i++], &status, 0)) > 0) { if(WIFEXITED(status)) printf("child %d terminated normally with exit status=%d\n", retpid,WEXITSTATUS(status)); else printf("child %d teminated abnormally\n", retpid); } if(errno != ECHILD) unix_error("waitpid error"); exit(0); }
12,sleep:将一个进程挂起一段时间。
pause:让函数休眠,直到该进程收到一个信号。
execve(char* filename, char* argv[], char* envp[]):在当前进程的上下文中加载并运行一个新进程。
它会覆盖当前进程的地址空间,但并没有创建一个新进程。有相同的PID,并继承了调用execve函数时打开的所有文件描述符。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[], char *envp[]) { int i; printf("Command line arguments:\n"); for(i=0;argv[i]!=NULL;i++) printf("argv[%2d]: %s\n", i, argv[i]); printf("\n"); printf("Environment viriables: \n"); for(i=0;envp[i]!=NULL;i++) printf("envp[%2d]: %s\n", i, envp[i]); exit(0); }
13,发送信号的原因:
(1)内核检测到一个系统事件。
(2)调用kill函数,显式要求内核发送一个信号给目的进程。
14,内核为每个进程在pending位向量维护者待处理信号集合。
而在blocked位向量维护着被阻塞的信号集合。
15,常见信号:
SIGINT:来自键盘的中断(ctrl+c)
SIGTSTP:来自键盘的暂停信号(ctrl+z)
SIGSTOP:不来自终端的暂停信号。
SIGCHLD:一个子进程暂停或终止。
SIGKILL:杀死进程。
SIGALRM:来自alarm函数的定时器信号
实例代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/stat.h> #include <errno.h> #include <sys/wait.h> void unix_error(char *msg) /* unix-style error */ { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid; } /* $begin kill */ void Kill(pid_t pid, int signum) { int rc; if ((rc = kill(pid, signum)) < 0) unix_error("Kill error"); } /* $end kill */ void Pause() { (void)pause(); return; } int main() { pid_t pid; if((pid=Fork()) == 0) { Pause();//挂起,直到收到一个信号 printf("Never here.\n"); exit(0); } Kill(pid, SIGKILL); //传递信号给子进程。 exit(0); }
16,unsigned int alarm(unsigned int secs):安排内核在secs秒内发送一个SIGALRM信号给调用进程。
返回:前一次闹钟剩余的秒数,对它的调用将会取消待处理的闹钟。
以前没有设定闹钟,返回0。
实例代码:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <ctype.h> #include <setjmp.h> #include <signal.h> #include <sys/time.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <errno.h> #include <math.h> #include <pthread.h> #include <semaphore.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> void unix_error(char *msg) /* unix-style error */ { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } typedef void handler_t(int); handler_t *Signal(int signum, handler_t *handler) { struct sigaction action, old_action; action.sa_handler = handler; sigemptyset(&action.sa_mask); /* block sigs of type being handled */ action.sa_flags = SA_RESTART; /* restart syscalls if possible */ if (sigaction(signum, &action, &old_action) < 0) unix_error("Signal error"); return (old_action.sa_handler); } unsigned int Alarm(unsigned int seconds) { return alarm(seconds); } void handler(int sig) { static int beeps = 0; printf("BEEP\n"); if(++beeps < 5) Alarm(1); else { printf("BOOM!\n"); exit(0); } } int main() { Signal(SIGALRM, handler); Alarm(1); while(1) ; exit(0); }
17,
typedef void handler_t(int);
handler_t *signal(int signum, handler_t *handler)
三种方法处理信号signum:
如果handler是SIG_IGN,那么忽略类型为signum的信号。
如果handler是SIG_DFL,默认行为。
信号处理程序。
18,非本地跳转。
int setjmp(jmp_buf env);//只调用一次,但返回很多次。
一次是第一次调用setjmp,栈的上下文保存在缓冲区env。
longjmp从env缓冲区中恢复栈的内容,从最近初始化env的setjmp调用返回。
实例代码:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <setjmp.h> jmp_buf buf; int error1 = 0; int error2 = 1; void bar(void) { if(error2) longjmp(buf, 2); } void foo(void) { if(error1) longjmp(buf, 1); bar(); } int main() { int rc; rc = setjmp(buf); if (rc == 0) foo(); else if (rc == 1) printf("Detected an error1 condition in foo\n"); else if (rc == 2) printf("Detected an error2 condition in foo\n"); else printf("Unknown error condition in foo\n"); exit(0); }
非本地跳转的另一个重要应用:使一个信号处理程序转移到一个特殊的代码位置。
而不是返回到被信号到达中断了的指令的位置。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <setjmp.h> #include <signal.h> #include <string.h> #include <errno.h> sigjmp_buf buf; void unix_error(char *msg) /* unix-style error */ { fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0); } unsigned int Sleep(unsigned int secs) { unsigned int rc; if ((rc = sleep(secs)) < 0) unix_error("Sleep error"); return rc; } typedef void handler_t(int); handler_t *Signal(int signum, handler_t *handler) { struct sigaction action, old_action; action.sa_handler = handler; sigemptyset(&action.sa_mask); /* block sigs of type being handled */ action.sa_flags = SA_RESTART; /* restart syscalls if possible */ if (sigaction(signum, &action, &old_action) < 0) unix_error("Signal error"); return (old_action.sa_handler); } void handler(int sig) { //这里的巧妙使用 siglongjmp(buf, 1); } int main() { Signal(SIGINT, handler); if(!sigsetjmp(buf, 1)) printf("starting\n"); else printf("restarting\n"); while(1) { Sleep(1); printf("processing...\n"); } exit(0); }
发表评论
-
虚拟存储器
2010-06-02 10:13 10211,虚拟存储器是硬件异 ... -
关于echo服务端和客户端
2010-05-23 11:22 83811,实现的基本功能: 客户端:发送一行文本给服务器,服务器显示 ... -
关于链接
2010-05-17 11:35 8711,加载器创建了存储器映像,将可执行文件的相关内容拷贝到了代码 ... -
内核对文件的管理
2010-05-15 13:48 9151,文件元数据。 stat结构体: struct stat ... -
关于Tiny Web服务器
2010-05-14 19:47 21971,一个静态内容的http事务: kmplayer@kmpla ... -
返回一段程序经过的CPU周期数
2010-05-10 10:44 9951,实例代码: #include <stdio.h& ...
相关推荐
在计算机科学中,异常控制流是程序执行过程中的一个重要概念,它涉及到操作系统、处理器硬件以及程序执行的流程。本章主要讨论的是在操作系统环境下,如Linux,如何管理和处理异常控制流。 首先,我们来看一下...
异常控制流II-信号 在计算机系统中,异常控制流是指在系统的不同层次上发生的控制流变化。这些变化可能来自于硬件、操作系统内核程序、进程上下文切换、硬件定时器、内核程序、应用程序等方面。异常控制流的种类...
在计算机科学中,异常控制流是指程序执行过程中由于异常事件(如硬件错误、软件中断或系统调用)导致的流程转移。这些异常可以发生在系统的所有层次,从硬件层面到操作系统内核,再到用户应用程序。本章《异常控制流...
异常控制流(ECF,Exception Control Flow)是操作系统中至关重要的一个概念,它涉及软件与硬件之间的交互,以及系统如何管理资源和服务请求。在本文中,我们将深入探讨ECF的基本概念,异常处理机制,以及其在操作...
csapp 第8章异常控制流 ---- xmind思维导图。 主要讲述了异常的概念,以及建立在此基础上的进程、信号、非本地跳转,以及相关的概念,如进程内存空间,进程组等等。
在学习笔记中,第七章至第九章主要探讨了链接、异常控制流和虚拟存储器这三个主题,这些都是构建现代计算机系统的关键组成部分。 **第七章:链接** 链接是将编译后的目标代码片段合并成可执行程序的过程。这一章...
为应对 APT 等漏洞利用攻击的问题,提出了一种基于异常控制流识别的漏洞利用攻击检测方法。该方法通过对目标程序的静态分析和动态执行监测,构建完整的安全执行轮廓,并限定控制流转移的合法目标,在函数调用、函数...
异常异常处理异常表异常处理程序运行在内核模式下异常的类别Linux/X86-64系统中的异常除法错误一般保护故障缺页机器检查Linux 中的系统调用进程一个执行
3. 异常控制流图的重要性:异常控制流图是程序分析和优化的重要工具,它可以帮助开发人员更好地理解程序的异常处理机制,并优化代码,提高软件的健壮性。 4. Eclipse插件设计的重要性:Eclipse插件设计可以帮助开发...
CPU的控制流通常由一系列指令构成,但在遇到如数据错误、用户中断或系统定时器到期等事件时,需要异常控制流来改变执行路径。异常控制流允许操作系统对程序状态的变化做出反应,如处理错误、响应外部事件或执行系统...
《深入理解计算机系统》是计算机科学领域的一门经典课程,主要涵盖了计算机系统的多个核心主题,包括信息表示、处理器体系结构、程序的机器级表示、存储器层次结构、虚拟内存以及异常控制流等。以下是根据提供的文件...
如果你不想紧紧只是作为一个普通的... 本书还介绍了有关:处理器体系结构, 优化程序性能, 存储层次结构, 链接, 异常控制流, 虚拟存储器, 网络编程, 系统级I/O,并发编程等方面的知识. 为了大家学习方便, 还附上了答案.
全书共12章,主要内容包括信息的表示和处理、程序的机器级表示、处理器体系结构、优化程序性能、存储器层次结构、链接、异常控制流、虚拟存储器、系统级I/O、网络编程、并发编程等。书中提供大量的例子和练习,并给...
全书共12章,主要包括信息的表示和处理、程序的机器级表示、处理器体系结构、优化程序性能、存储器层次结构、链接、异常控制流、虚拟存储器、系统级I/0、网络编程、并发编程等内容。书中提供了大量的例子和练习题,...
1. **第8章 异常控制流I-异常和进程**: - 异常:当系统遇到不可预期的情况(如除零错误、硬件故障或软件中断)时,会触发异常。异常处理机制允许系统安全地处理这些错误,同时保持程序的正常执行流程。 - 进程:...
2. **第8章 异常控制流I-异常和进程(新).pdf**:这部分内容涉及操作系统中的异常和进程管理。异常是处理器在遇到错误或特定条件时触发的中断,如除零错误、硬件故障等;进程则是操作系统中运行程序的抽象,它包括...
全书共12章,主要内容包括信息的表示和处理、程序的机器级表示、处理器体系结构、优化程序性能、存储器层次结构、链接、异常控制流、虚拟存储器、系统级I/O、网络编程、并发编程等。书中提供子大量的例子和练习题,...