版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第七講為用戶編程:終端控制和信號1主要內(nèi)容軟件工具與用戶程序讀取和修改終端驅(qū)動程序的設(shè)置非阻塞輸入用戶輸入的超時信號fcntl及signal系統(tǒng)調(diào)用2與終端有關(guān)的程序用戶常用的程序例如vi、emacs及許多游戲程序經(jīng)常要有終端進行交互它們設(shè)置終端驅(qū)動程序的擊鍵和輸出處理方式用戶經(jīng)常用到的幾種用戶終端設(shè)置:立即響應(yīng)擊鍵事件有限的輸入集輸入的超時屏蔽Ctrl-C3終端驅(qū)動程序的模式/*rotate.c*/#include<stdio.h>#include<ctype.h>intmain(){intc;while((c=getchar())!=EOF){if(c==‘z’)c=‘a(chǎn)’elseif(islower(c))c++;putchar(c);}4規(guī)范模式:緩沖和編輯使用默認設(shè)置運行該程序(<-退格鍵)$gccrotate.c-orotate$./rotateabx<-cdbcdeefg^C$5輸入的內(nèi)容及程序所得到的內(nèi)容
rotate程序終端驅(qū)動程序顯示器及鍵盤6標準輸入處理的特征程序未得到輸入的x,因為刪除了它擊鍵的同時字符顯示在屏幕上,但直到按了回車,程序才接收到輸入^C鍵結(jié)束輸入并終止程序程序rotate并不負責(zé)這些事情,對于輸入的緩沖、回顯、編輯和控制鍵處理都由驅(qū)動程序完成標準輸入處理的這些特征被啟動時,將終端連接稱為規(guī)范模式7非規(guī)范處理$stty-icanon;./rotateabbcxy^?cddeeffggh$sttyicanonstty-icanon命令關(guān)閉驅(qū)動程序中的規(guī)范模式處理非規(guī)范模式?jīng)]有緩沖,輸入字母’a’,驅(qū)動程序跳過緩沖層,字符直接送到程序,然后程序顯示字符’b’用戶輸入未緩沖可能會帶來麻煩,如果用戶想修改輸入時,此時將無法修改8終端模式小結(jié)--規(guī)范模式
是用戶常見的模式輸入的字符保存在緩沖區(qū)接收到回車鍵時才將其中內(nèi)容發(fā)送到程序緩沖功能使驅(qū)動程序可實現(xiàn)編輯功能,例如刪除字符、單詞或者行可通過命令stty或者系統(tǒng)調(diào)用tcsetattr修改執(zhí)行上述操作的特定鍵9終端模式小結(jié)--非規(guī)范模式
緩沖和編輯功能被關(guān)閉時,連接被稱為處于非規(guī)范模式設(shè)備驅(qū)動器仍然進行特定字符的處理,例如Ctrl-C及換行符及回車符之間的轉(zhuǎn)換刪除單詞、字符及終止編輯鍵將不具有特殊含義而是被視作常規(guī)的數(shù)據(jù)輸入10終端模式小結(jié)--raw模式
每個處理步驟都被一個獨立的位控制,例如ISIG位控制Ctrl-C是否用于終止一個程序程序可隨意關(guān)閉所有這些處理步驟當(dāng)所有處理都被關(guān)閉后,驅(qū)動程序?qū)⑤斎胫苯觽鬟f給程序。這種模式就稱為raw模式sttyraw命令11編寫一個用戶程序:play_again.cplay_again.c的邏輯:對用戶顯示提示問題接受輸入如果是y返回0如果是n返回1第一個play_again0.c程序12play_again0.c的不足必須先按回車,程序才能接受到數(shù)據(jù)當(dāng)用戶按回車鍵時,程序接收整行的數(shù)據(jù)對其進行處理,例如Doyouwantanothertransaction(y/n)?surethingsurething13改進方法首先關(guān)閉規(guī)范輸入,使得程序能夠在用戶敲鍵的同時得到輸入的字符set_crmode(){structtermiosttystate;tcgetattr(0,&ttystate); /*readcurr.setting */ttystate.c_lflag&=~ICANON; /*nobuffering */ttystate.c_cc[VMIN]=1; /*get1charatatime */tcsetattr(0,TCSANOW,&ttystate); /*installsettings */}14tty_mode(inthow)staticstructtermiosoriginal_mode;if(how==0) tcgetattr(0,&original_mode);elsereturntcsetattr(0,TCSANOW,&original_mode);15程序的主要過程首先調(diào)用tty_mode(0)函數(shù)保存當(dāng)前終端的設(shè)置信息set_crmode()函數(shù)首先將終端置于一個字符接一個字符的模式然后調(diào)用函數(shù)顯示一個提示符,并獲得一個響應(yīng)最后調(diào)用tty_mode(1)函數(shù)還原終端的設(shè)置16將終端置入字符輸入模式包括兩部分工作:將ICANON位關(guān)閉將控制字符數(shù)組中的VMIN下標元素置一,VMIN的值告訴驅(qū)動程序一次可以讀取多少個字符17編譯執(zhí)行play_again1程序此時,程序可以直接接收和處理字符而不用等待回車鍵但對每個非法字符都提示錯誤信息,可能比較煩可關(guān)閉回顯模式,丟掉不需要的字符,直到得到可接收的字符為止在set_crmode函數(shù)中加入語句ttystate.c_lflag&=~ECHO;18阻塞與非阻塞輸入當(dāng)調(diào)用getchar或者read等函數(shù)從文件描述符讀數(shù)據(jù)時,這些調(diào)用一直等待用戶的輸入,如果用戶不輸入,則繼續(xù)等待,這種行為就術(shù)語阻塞輸入阻塞不僅僅是終端連接的屬性,而且是任何一個打開文件的屬性可使用fcntl或者open,通過開啟O_NDELAY標志為文件描述符啟動非阻塞輸入。19非阻塞讀取文件關(guān)閉文件描述符的阻塞狀態(tài),然后從中read時,結(jié)果如何呢?如果能夠獲得輸入,read返回輸入數(shù)據(jù)及字符個數(shù),如果沒有輸入字符,read返回0,就像遇到文件末尾一樣,有錯誤,返回-1.每個文件都有一塊保存未讀取數(shù)據(jù)的地方,若文件描述符置了O_NDELAY并且該空間為空,則read返回0。20play_again3.cget_response(){int input;printf("%s(y/n)?",question); /*ask */fflush(stdout); /*forceoutput */while(1){ sleep(SLEEPTIME); /*waitabit */ input=tolower(get_ok_char()); /*getnextchr*/ if(input=='y') return0; if(input=='n') return1; if(maxtries--==0) /*outatime? */ return2; /*sayso */ BEEP; }}21實驗結(jié)果在輸入后,程序會延時一會兒如果長時間不輸入,程序也會退出22fflush(out)函數(shù)終端驅(qū)動對于輸出也是一行行緩沖的直到它收到一個換行符或者程序試圖從終端讀取數(shù)據(jù)時才會進行輸出而此時getchar被延遲讀入,因此通過該函數(shù)將提示信息輸出到屏幕上,否則用戶將看不到提示信息。23Ctrl-C執(zhí)行上述程序時,如果輸入Ctrl-C則程序終止運行,同時,也終止了整個登錄會話原因是什么呢?24Ctrl-C設(shè)置O_NDELAY設(shè)置crmode顯示提示符等待用戶輸入用戶輸入恢復(fù)tty設(shè)置恢復(fù)fcntl標志退出程序流程CtrlC進程被終止進程正常退出時流向25Ctrl-C程序接收到Ctrl-C后,會立即退出,此時,無法執(zhí)行重置啟動程序的代碼返回shell并從用戶獲得命令行時,終端仍處于非阻塞模式。shell調(diào)用read獲取命令行,但是因為處于非阻塞狀態(tài),read立即返回0.這時shell程序就退出原因總結(jié):程序結(jié)束時,文件描述符處于一個錯誤的狀態(tài)。26信號Ctrl-C中斷當(dāng)前運行的程。這個中斷由內(nèi)核的信號機制產(chǎn)生Ctrl-C的過程:用戶輸入Ctrl-C驅(qū)動程序收到字符匹配VINTR和ISIG的字符被開啟驅(qū)動程序調(diào)用信號系統(tǒng)信號系統(tǒng)發(fā)送SIGINT到進程進程收到SIGINT進程消亡27什么是信號信號是由單個詞組成的消息,例如紅綠燈所發(fā)出的信息Ctrl-C時,內(nèi)核向當(dāng)前運行的進程發(fā)送中斷信號每個信號都有一個數(shù)字編碼。中斷信號編碼通常是228信號的來源信號來自內(nèi)核生成信號的請求來自3個地方:用戶--通過輸入Ctrl-C、Ctrl-\等請求內(nèi)核產(chǎn)生信號內(nèi)核--進程執(zhí)行出錯時,內(nèi)核向進程發(fā)送一個信號,例如非法段訪問、浮點數(shù)溢出等,也可通知進程特定事件的發(fā)生。進程--通過系統(tǒng)調(diào)用kill給另一個進程發(fā)送信號。進程之間可通過信號通信29同步與異步信號由進程的某個操作產(chǎn)生的信號稱為同步信號,例如被零除用戶擊鍵這樣的進程外的事件引起的信號稱為異步信號30信號列表信號編號及其名字可在/usr/include/signal.h文件中找到,例如SIGINT為中斷信號,SIGQUIT退出信號,SIGSEGV非法段訪問信號可以使用信號消滅一個進程,也有辦法保護自己不被殺死31進程處理信號的方法進程通過signal系統(tǒng)調(diào)用告訴內(nèi)核如何處理信號進程有3個選擇:(1)接受默認處理SIGINT默認處理為消亡,進程通過系統(tǒng)調(diào)用signal(SIGINT,SIG_DFL)恢復(fù)默認處理(2)忽略信號signal(SIGINT,SIG_IGN)系統(tǒng)調(diào)用告訴內(nèi)核忽略該信號32進程處理信號的方法(3)調(diào)用一個函數(shù),這是3種方法中最強大的一個。例如在play_again3程序中,當(dāng)用戶輸入Ctrl-C時,程序收到信號后執(zhí)行一個恢復(fù)設(shè)置的函數(shù)就不會發(fā)生上述情況了程序能夠告訴內(nèi)核,當(dāng)信號來時調(diào)用哪個函數(shù),signal(SIGINT,function);信號到來時所調(diào)用的函數(shù)稱為信號處理函數(shù)33signal系統(tǒng)調(diào)用目標簡單的信號處理頭文件#include<signal.h>函數(shù)原型result=signal(intsignum,void(*action)(int));參數(shù)signum需響應(yīng)的信號action如何響應(yīng)返回值-1遇到錯誤prevaction返回之前的處理函數(shù)指針34signal系統(tǒng)調(diào)用其中action可以是函數(shù)名也可以是如下兩種特殊值之一:SIG_IGN,忽略信號SIG_DFL將信號恢復(fù)為默認處理signal返回前一個處理函數(shù)。值為指向該函數(shù)的指針35信號處理的例子sigdemo1.c
#include <stdio.h>#include <signal.h>main(){ void f(int); /*declarethehandler */ int i; signal(SIGINT,f); /*installthehandler */ for(i=0;i<5;i++){ /*dosomethingelse */ printf("hello\n"); sleep(1); }}voidf(intsignum) /*thisfunctioniscalled*/{ printf("OUCH!\n");}36信號處理過程main(){signal(SIGINT,f);for(i=0;i<5;i++){printf(“hello\n”);sleep(1);}}正常控制流信號函數(shù)f(){printf(“OUCH”);}37sigdemo1.c執(zhí)行結(jié)果hellohellohellohello^COUCH!hello38忽略信號sigdemo2.c
#include <stdio.h>#include <signal.h>main(){ signal(SIGINT,SIG_IGN); printf("youcan'tstopme!\n"); while(1) { sleep(1); printf("haha\n"); }}39sigdemo2.c程序執(zhí)行結(jié)果youcan'tstopme!hahahaha^Chahahaha^Chahahaha^\退出40sigdemo2.c調(diào)用signal忽略中斷信號,可以隨意按Ctrl-C而不會對程序產(chǎn)生影響signal(SIGINT,SIG_IGNT)41作業(yè)6.1042處理多個信號當(dāng)有多個信號到達進程時,該如何處理?431.捕鼠器問題
信號處理函數(shù)有點像捕鼠器早期版本中,在每次捕獲之后,都必須重設(shè)它們。例如voidhandler(ints){signal(SIGINT,handler);}441.捕鼠器問題即使設(shè)置的速度非常快,它還是需要時間觸發(fā)處理函數(shù)及重新設(shè)置完成之前,有新的信號或者老鼠溜走這一脆弱的間隙使得原有的信號處理不可靠,因此稱為不可靠的信號45處理多個信號第二個信號打斷第一個信號的處理第二個信號被阻塞返回信號處理的地方是否要重新開始?信號的優(yōu)先級?46進程的多個信號處理函數(shù)每次使用之后都要禁用嗎?如果SIGY消息在進程處理SIGX消息時到達會發(fā)生什么?如果進程還在處理前一個SIGX時,第二個SIGX又到來會發(fā)生什么事情呢?第三個呢?如果信號到來時,程序正在處理getchar或者read之類的輸入而阻塞,那會如何呢?47測試多個信號sigdemo3.c程序signal(SIGINT,inthandler); /*sethandler*/signal(SIGQUIT,quithandler); /*sethandler*/do{ printf("\nTypeamessage\n"); nchars=read(0,input,(INPUTLEN-1)); if(nchars==-1) perror("readreturnedanerror"); else{ input[nchars]='\0'; printf("Youtyped:%s",input); }}while(strncmp(input,"quit",4)!=0);}48voidinthandler(ints){ printf("Receivedsignal%d..waiting\n",s); sleep(2); printf("Leavinginthandler\n");}voidquithandler(ints){ printf("Receivedsignal%d..waiting\n",s); sleep(3); printf("Leavingquithandler\n");}49執(zhí)行結(jié)果Typeamessagehelloyoutyped:helloTypeamessage^\^CReceivedsignal3....Receivedsignal2....LeavinginthandlerLeavingquithandler50各種實驗(1)輸入^C^C^C^C(2)^\^C^\^C(3)hello^CReturn(4)helloReturn^C(5)^\^\hello^C51第一種情況不可靠的信號若兩個SIGINT信號殺死了進程,則系統(tǒng)是不可靠的信號若未殺死進程,則處理函數(shù)在被調(diào)用后還有作用現(xiàn)代信號處理機制允許在兩者之間選擇默認情況下,為后者第一次實驗的結(jié)果為:信號函數(shù)執(zhí)行了兩次,后面的兩次函數(shù)丟失52第二種情況:SIGY打斷SIGX的處理
函數(shù)接連按下^C和^\時程序先跳到inthandler,然后跳到quithandler,然后再回到inthandler,最后回到主循環(huán)第二種情況的實驗:接收到^\后,程序進入quithandler程序,接收到^C后,進入inthandler程序,最后返回到quithandler程序說明信號^C打斷信號^\53第三種情況:SIGX打斷SIGX的處理函數(shù)有三種可能:遞歸,調(diào)用同一個處理函數(shù)忽略第二個信號阻塞第二個信號直到第一個處理完畢第三種方法最好,54系統(tǒng)調(diào)用被中斷例如當(dāng)調(diào)用read或者getchar函數(shù)時,程序接收到^C的信號然后程序執(zhí)行信號處理函數(shù),執(zhí)行完后,程序重新返回主循環(huán)程序是重新執(zhí)行read還是從read返回同時設(shè)置errno為EINTR呢?55實驗結(jié)果:hello^CReturn時,程序無法接收到hello輸入helloReturn^C時,程序可接收到hellohel^CloReturn時,程序只接收到lo^\^\hello^C時,無法得到hello輸入,同時信號處理執(zhí)行完后,重新開始read56信號機制其他的弱點無法確定信號產(chǎn)生的原因---早期的模型只是告訴了信號的類型處理函數(shù)中無法安全阻塞其他消息voidinthandler(ints){intrv;void(*prev_qhandler)();prev_qhandler=signal(SIGQUIT,SIG_IGN);….signal(SIGQUIT,prev_qhandler);}57無法同時調(diào)用inthandler以及忽略SIGQUIT無法阻塞SIGQUIT信號58sigaction可以處理多個信號目標指定信號的處理函數(shù)頭文件#include<signal.h>函數(shù)原型result=signaction(intsignum,conststructsigaction*actionstructsigaction*prevaction));參數(shù)signum需處理的信號action指向描述操作的結(jié)構(gòu)的指針prevaction指向描述被替換操作的結(jié)構(gòu)指針返回值-1遇到錯誤0成功59定制信號處理structsigactionstructsigaction{void(*sa_handler)();void(*sa_sigaction)(int,siginfo_t*,void*);sigset_tsa_mask;intsa_flags;}其中sa_handler可以為SIG_DFL,SIG_IGN或者函數(shù)名稱,它是老的信號處理方式60sa_sigaction為新的信號處理機制它可獲得信號編號及被調(diào)用的原因及產(chǎn)生問題的上下文的相關(guān)信息使用舊的處理機制:structsigactionaction;action.sa_handler=handler_old;使用新的處理機制:structsigactionaction;action.sa_sigaction=handler_new;將sigaction中的標志位sa_flags置為:SA_SIGINFO61sa_flags標志標記含義SA_RESETHAND當(dāng)處理函數(shù)被調(diào)用時重置,即捕鼠器模式SA_NODEFER處理信號時關(guān)閉信號自動阻塞,因此允許遞歸調(diào)用信號處理函數(shù)SA_RESTART當(dāng)系統(tǒng)調(diào)用是針對一些慢速的設(shè)備或類似的系統(tǒng)調(diào)用,重新開始而不是返回SA_SIGINFO指明使用sa_sigaction的處理函數(shù)值。如果它未設(shè)置,則使用舊處理機制,若設(shè)置,則傳給處理函數(shù)的包括信號編號、信號產(chǎn)生的原因和條件等信息62sigaction的例子 structsigactionnewhandler;/*newsettings*/ sigset_tblocked;/*setofblockedsigs*/ void inthandler();/*thehandler*/ char x[INPUTLEN]; /*loadthesetwomembersfirst*/ newhandler.sa_handler=inthandler;/*handlerfunction*/ newhandler.sa_flags=SA_RESETHAND|SA_RESTART;/*options*/ /*thenbuildthelistofblockedsignals*/ sigemptyset(&blocked);/*clearallbits*/ sigaddset(&blocked,SIGQUIT); /*addSIGQUITtolist*/ newhandler.sa_mask=blocked;/*storeblockmask*/ if(sigaction(SIGINT,&newhandler,NULL)==-1) perror("sigaction");63防止數(shù)據(jù)損毀臨界區(qū)修改一個數(shù)據(jù)結(jié)構(gòu)的代碼若在運行時被打斷,將導(dǎo)致數(shù)據(jù)的不完整或損毀該代碼稱為臨界區(qū)臨界區(qū)不一定就在信號處理函數(shù)中保護它的最簡單的辦法就是忽略或阻塞處理函數(shù)將要使用或修改特定數(shù)據(jù)的信號64阻塞信號:sigprocmask和sigsetop
在信號處理一級或者進程一級阻塞信號在處理一個信號時阻塞另一個信號,設(shè)置structsigaction中的sa_mask成員位sa_mask指定哪些信號要被阻塞sa_mask類型為sigset_t,它定義了信號集合65進程的阻塞信號任何時候進程都有一些信號被阻塞,這個信號的集合被稱為信號擋板。系統(tǒng)調(diào)用sigprocmask可修改這個被阻塞的信號集sigprocmask是一個原子操作,根據(jù)所給的信號集來修改當(dāng)前被阻塞的信號集66sigprocmask目標修改當(dāng)前的信號擋板頭文件#include<signal.h>函數(shù)原型intresult=sigprocmask(inth
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 小學(xué)衛(wèi)生宣教制度
- 衛(wèi)生室聯(lián)合用藥管理制度
- 鎮(zhèn)鄉(xiāng)中心校食品衛(wèi)生制度
- 小學(xué)德育衛(wèi)生制度
- 衛(wèi)生院信息反饋制度
- 衛(wèi)生站院感巡查制度
- 衛(wèi)生系統(tǒng)雙報告制度
- 鄉(xiāng)鎮(zhèn)衛(wèi)生院重精工作制度
- 熟制品衛(wèi)生管理制度
- 焊錫職衛(wèi)生管理制度
- 2023-2024學(xué)年廣東省茂名市高一(上)期末數(shù)學(xué)試卷(含答案)
- 《課堂管理的技巧》課件
- 醫(yī)院培訓(xùn)課件:《頸椎病》
- 佛山市離婚協(xié)議書范本
- HG+20231-2014化學(xué)工業(yè)建設(shè)項目試車規(guī)范
- 工地春節(jié)停工復(fù)工計劃安排方案
- 連接員題庫(全)題庫(855道)
- 單元學(xué)習(xí)項目序列化-選擇性必修下冊第三單元為例(主題匯報課件)-統(tǒng)編高中語文教材單元項目式序列化研究
- 黑布林英語漁夫和他的靈魂
- 電站組件清洗措施及方案
- 冀教版五年級英語下冊全冊同步練習(xí)一課一練
評論
0/150
提交評論