找出全書你認爲學得最差的一章,深刻從新學習一下,要求(期末佔5分):html
總結新的收穫git
給你的結對學習搭檔講解或請教,並獲取反饋數組
8.1 異常緩存
異常就是控制流中的突變,用來響應處理器狀態中的某些變化。安全
異常控制流:現代系統經過使控制流發生突變來對這些狀況做出反應。數據結構
平滑:指在存儲器中指令都是相鄰的。併發
突變:出現不相鄰,一般由諸如跳轉、調用、和返回等指令形成。異步
異常控制流ECF:即這些突變。函數
8.1.1 異常處理工具
系統中可能的每種類型的異常都分配了一個惟一的非負整數的異常號。
關於ECF:
1.ECF是操做系統用來實現I/O、進程和虛擬存器的基本機制 2.應用程序經過使用一個叫作陷阱或者系統調用的ECF形式,向操做系統請求服務 3.ECF是計算機系統中實現併發的基本機制 4.軟件異常機制——C++和Java有try,catch,和throw,C中非本地跳轉是setjmp和longjmp
異常號的分配:
一、處理器的設計者:被除零、缺頁、存儲器訪問違例、斷點以及算數溢出。
二、操做系統內核的設計者分配的:系統調用和來自意外的I/O設備的信號。
異常號:到異常表中的索引異常表基址寄存器:異常表的起始地址存放的位置。三、異常與過程調用的異同:
一、過程調用時,在跳轉處處理器以前,處理器將返回地址壓入棧中。然而,根據異常的類型,返回地址要麼是當前指令,要麼是下一條指令。
二、處理器把一些額外的處理器狀態壓入棧裏,在處理程序返回時,從新開始被中斷的程序會須要這些狀態。
三、若是控制從一個用戶程序轉移到內核,那麼全部這些項目都被壓到內核棧中,而不是壓到用戶棧中。
四、異常處理程序運行在內核模式下,意味着它們對全部的系統資源都有徹底的訪問權限。
出現異常的處理方式:
1.處理器檢測到有異常發生 2.經過異常表,進行間接過程調用,到達異常處理程序 3.完成處理後:①返回給當前指令②返回給下一條指令③終止
8.1.2異常的類別
中斷: 來自I/O設備的信號,異步,老是返回到下一條指令
陷阱: 有意的異常,同步,老是返回到下一條指令
故障: 潛在可恢復的錯誤,同步,可能返回到當前指令
終止: 不可恢復的錯誤,同步,不會返回
故障指令:執行當前指令致使異常
中斷處理程序:硬件中斷的異常處理程序。
8.2 進程
異常是容許操做系統提供進程的概念所須要的基本構造塊。
進程:一個執行中的程序的實例。
上下文是由程序正確運行所須要的狀態組成的,這個狀態包括存放在存儲器中的程序的代碼和數據,它的棧、通用目的寄存器的內容、程序計數器、環境變量以及打開文件描述符的集合。
進程提供給應用程序的關鍵抽象:一個獨立的邏輯控制流,獨佔地使用處理器;一個私有的地址空間,獨佔地使用存儲器系統。
一共有256種不一樣的異常類型。
8.2.1 邏輯控制流
程序計數器:惟一的對應於包含在程序的可執行目標文件中的指令,或者是包含在運行時動態連接到程序的共享對象中的指令。這個PC值的序列叫作邏輯控制流,簡稱邏輯流。
8.2.2 併發流
併發流:一個邏輯流的執行在時間上與另外一個流重疊。
併發:多個流併發地執行的通常現象。
多任務:一個進程和其餘進程輪流運行的概念。
時間片:一個進程執行它的控制流的一部分的每一時間段。
多任務也叫時間分片。
並行流:若是兩個流併發的運行在不一樣的處理器核或者計算機上
8.2.3 私有地址空間
這個空間中某個地址相關聯的那個存儲器字節是不能被其餘進程讀或者寫的
8.2.4 用戶模式和內核模式
當設置了模式位時,進程就運行在內核模式中
沒有設置模式位時,進程就運行在用戶模式中。用戶模式中的進程不容許執行特權指令。
進程從用戶模式變位內核模式的惟一方法是經過諸如中斷、故障或者陷入系統調用這樣的異常。 /proc文件系統容許用戶模式進程訪問內核數據結構的內容
8.2.5 上下文切換
上下文切換:是較高形式的異常控制流來實現多任務
調度:在進程執行的某些時刻,內核能夠決定搶佔當前進程,並從新開始一個先前被搶佔的進程。這種決定叫作調度
當內核表明用戶執行系統調用時,可能會發生上下文切換。若是系統調用由於等待某個事件發生阻塞,那麼內核可讓當前進程休眠,切換到另外一個進程
中斷也可能引起上下文切換
8.3 系統調用錯誤處理
錯誤處理包裝函數:包裝函數調用基本函數,檢查錯誤,若是有任何問題就終止。 8.4 進程控制
8.4.1獲取進程ID
每一個進程都有一個惟一的正數進程ID gitpid函數返回調用進程的PID,getppid函數返回它的父進程的PID(建立調用進程的進程)
#include<sys/types.h> #include<unistd.h> pid_t getpid(void); pid_t getppid(void);
8.4.2 建立和終止進程
進程狀態:運行、中止、終止 exit函數以status退出狀態來終止進程
fork函數
父進程經過調用fork函數建立一個新的運行子進程 當父進程調用fork時,子進程能夠讀寫父進程中打開的任何文件 父進程和子進程之間最大的區別在於有不一樣的PID 調用一次,返回兩次 併發執行 相同可是獨立的地址空間 共享文件
#include<sys/types.h> #include<sys/wait.h> pid_t waitpid(pid_t pid,int *status,int options);
一、斷定等待集合的成員(由參數pid肯定) pid>0,等待集合就是一個單獨的子進程,它的進程ID等於pid pid=-1,等待集合就是由父進程全部的子進程組成的
二、修改默認行爲 WNOHANG:默認行爲是掛起調用進程,直到有子進程終止 WUNTRCED:默認行爲是隻返回已經終止的子進程 WNOHANG|WUNTRCED:當即返回
三、檢查已回收子進程的退出狀態
四、錯誤條件 若是調用進程沒有子進程,那麼waitpid返回-1,設置errno爲ECHILD 若是waidpid函數被一個信號中斷,那麼它返回-1,並設置errno爲EINTR
五、wait函數
六、使用waitpid的示例
8.4.4 讓進程休眠
sleep函數將一個進程掛起一段指定的時間
#include<unistd.h> unsigned int sleep(unsigned int secs);
#include<unisted.h> int pause(void);
execve函數
在當前進程的上下文中加載並運行一個新程序,execve
調用一次並從不返回 argv參數列表,envp環境變量getenv函數
8.5 信號
底層的硬件異常是由內核異常處理程序處理的,正常狀況下,對用戶進程而言是不可見的。
其餘信號對應於內核或者其餘用戶進程中較高層的軟件事件
8.5.1 信號術語
發送信號的兩個不一樣步驟:
一、發送信號:內核經過更新目的進程上下文中的某個狀態,發送(遞送)一個信號給目的進程。
二、接收信號:信號處理程序捕獲信號的基本思想。
發送信號的兩個緣由:
一、內核監測到一個系統事件,好比被零除錯誤或者子進程終止。
二、一個進程調用了kill函數,顯式地要求內核發送一個信號給目的進程。一個進程能夠發送信號給它本身。
待處理信號:一個只發出而沒有被接收的信號
一、一個進程能夠有選擇性地阻塞接收某種信號。
二、待處理信號不會被接收,直到進程取消對這種信號的阻塞。
一個待處理信號最多隻能被接受一次,pending位向量:維護着待處理信號集合,blocked向量:維護着被阻塞的信號集合。
非本地跳轉
c語言中,用戶級的異常控制流形式,經過setjmp和longjmp函數提供。
setjump函數在env緩衝區中保存當前調用環境,以供後面longjmp使用,並返回0.
調用環境:程序計數器,棧指針,通用目的寄存器
longjmp函數從env緩衝區中恢復調用環境,而後觸發一個從最近一次初始化env的setjmp調用的返回。而後setjmp返回,並帶有非零的返回值retval。
注:
setjmp函數只被調用一次,但返回屢次;
longjmp函數被調用一次,但從不返回。
操做進程的工具
STRACE:打印一個正在運行的程序和他的子程序調用的每一個系統調用的痕跡
PS:列出當前系統中的進程,包括僵死進程
TOP:打印出關於當前進程資源使用的信息
PMAP:顯示進程的存儲器映射
exec1
#include <unistd.h> int main() { char *arglist[3]; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0 ;//NULL printf("* * * About to exec ls -l\n"); execvp( "ls" , arglist ); printf("* * * ls is done. bye"); return 0; }

exec2
#include <stdio.h> #include <unistd.h> int main() { char *arglist[3]; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0 ; printf("* * * About to exec ls -l\n"); execvp( arglist[0] , arglist ); printf("* * * ls is done. bye\n"); }
exec3
#include <stdio.h> #include <unistd.h> int main() { char *arglist[3]; char *myenv[3]; myenv[0] = "PATH=:/bin:"; myenv[1] = NULL; arglist[0] = "ls"; arglist[1] = "-l"; arglist[2] = 0 ; printf("* * * About to exec ls -l\n"); // execv( "/bin/ls" , arglist ); // execvp( "ls" , arglist ); // execvpe("ls" , arglist, myenv); execlp("ls", "ls", "-l", NULL); printf("* * * ls is done. bye\n"); }
forkdemo1
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main() { int ret_from_fork, mypid; mypid = getpid(); printf("Before: my pid is %d\n", mypid); ret_from_fork = fork(); sleep(1); printf("After: my pid is %d, fork() said %d\n", getpid(), ret_from_fork); return 0; }
forkdemo2
#include <stdio.h> #include <unistd.h> int main() { printf("before:my pid is %d\n", getpid() ); fork(); fork(); printf("aftre:my pid is %d\n", getpid() ); return 0; }
forkdemo3
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int fork_rv; printf("Before: my pid is %d\n", getpid()); fork_rv = fork(); /* create new process */ if ( fork_rv == -1 ) /* check for error */ perror("fork"); else if ( fork_rv == 0 ){ printf("I am the son. my pid=%d\n", getpid()); exit(0); } else{ printf("I am the father. my son is %d\n", fork_rv); exit(0); } return 0; }
forkdemo4
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int fork_rv; printf("Before: my pid is %d\n", getpid()); fork_rv = fork(); /* create new process */ if ( fork_rv == -1 ) /* check for error */ perror("fork"); else if ( fork_rv == 0 ){ printf("I am the son. my pid=%d\n", getpid()); printf("parent pid= %d, my pid=%d\n", getppid(), getpid()); exit(0); } else{ printf("I am the father. my son is %d\n", fork_rv); sleep(10); exit(0); } return 0; }
forkgdb
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int gi=0; int main() { int li=0; static int si=0; int i=0; pid_t pid = fork(); if(pid == -1){ exit(-1); } else if(pid == 0){ for(i=0; i<5; i++){ printf("son li:%d\n", li++); sleep(1); printf("son gi:%d\n", gi++); printf("son si:%d\n", si++); } exit(0); } else{ for(i=0; i<5; i++){ printf("father li:%d\n", li++); printf("father gi:%d\n", gi++); sleep(1); printf("father si:%d\n", si++); } exit(0); } return 0; }
psh1
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define MAXARGS 20 #define ARGLEN 100 int execute( char *arglist[] ) { execvp(arglist[0], arglist); perror("execvp failed"); exit(1); } char * makestring( char *buf ) { char *cp; buf[strlen(buf)-1] = '\0'; cp = malloc( strlen(buf)+1 ); if ( cp == NULL ){ fprintf(stderr,"no memory\n"); exit(1); } strcpy(cp, buf); return cp; }
psh2
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> #define MAXARGS 20 #define ARGLEN 100 char *makestring( char *buf ) { char *cp; buf[strlen(buf)-1] = '\0'; cp = malloc( strlen(buf)+1 ); if ( cp == NULL ){ fprintf(stderr,"no memory\n"); exit(1); } strcpy(cp, buf); return cp; } void execute( char *arglist[] ) { int pid,exitstatus; pid = fork(); switch( pid ){ case -1: perror("fork failed"); exit(1); case 0: execvp(arglist[0], arglist); perror("execvp failed"); exit(1); default: while( wait(&exitstatus) != pid ) ; printf("child exited with status %d,%d\n", exitstatus>>8, exitstatus&0377); } } int main() { char *arglist[MAXARGS+1]; int numargs; char argbuf[ARGLEN]; numargs = 0; while ( numargs < MAXARGS ) { printf("Arg[%d]? ", numargs); if ( fgets(argbuf, ARGLEN, stdin) && *argbuf != '\n' ) arglist[numargs++] = makestring(argbuf); else { if ( numargs > 0 ){ arglist[numargs]=NULL; execute( arglist ); numargs = 0; } } } return 0; }
一、Y86-64中()指令沒有訪存操做.
A . rrmovl
B . irmovq
C . rmmovq
D . pushq
E . jXX
F . ret
正確答案: A B E
二、The following table gives the parameters for a number of different caches. For each cache, determine the number of cache sets (S), tag bits (t), set index bits (s), and block offset bits (b)
A . 第三行S爲1
B . 第一行t爲24
C . 第二行s爲5
D . 第三行b的值爲5
正確答案: A C D
三、有關磁盤操做,說法正確的是()
A . 對磁盤扇區的訪問時間包括三個部分中,傳送時間最小。
B . 磁盤以字節爲單位讀寫數據
C . 磁盤以扇區爲單位讀寫數據
D . 讀寫頭總處於同一柱面
正確答案: A C D
錯誤總結: 磁盤操做中,讀寫頭總處於同一柱面。
四、有關RAM的說法,正確的是()
A . SRAM和DRAM掉電後均沒法保存裏面的內容。
B . DRAM將一個bit存在一個雙穩態的存儲單元中
C . 通常來講,SRAM比DRAM快
D . SRAM經常使用來做高速緩存
E . DRAM將每個bit存儲爲對一個電容充電
F . SRAM須要不斷刷新
G . DRAM被組織爲二維數組而不是線性數組
正確答案: A C D E G
錯誤總結: SRAM經常使用來做高速緩存(SRAM:靜態隨機存取存儲器)
此次的博客是本身選一章以爲本身以前學的比較差的進行再一次學習,因此此次的學習就要更加的深刻,更加的詳細,將上次遺留的問題進行解決,此次的收穫也特別大,並且此次也和接伴對象一塊兒學習,收穫也很大。