为用户编程:终端控制和.ppt

上传人:sh****n 文档编号:13183618 上传时间:2020-06-06 格式:PPT 页数:74 大小:453KB
返回 下载 相关 举报
为用户编程:终端控制和.ppt_第1页
第1页 / 共74页
为用户编程:终端控制和.ppt_第2页
第2页 / 共74页
为用户编程:终端控制和.ppt_第3页
第3页 / 共74页
点击查看更多>>
资源描述
第七讲为用户编程:终端控制和信号,主要内容,软件工具与用户程序读取和修改终端驱动程序的设置非阻塞输入用户输入的超时信号fcntl及signal系统调用,与终端有关的程序,用户常用的程序例如vi、emacs及许多游戏程序经常要有终端进行交互它们设置终端驱动程序的击键和输出处理方式用户经常用到的几种用户终端设置:立即响应击键事件有限的输入集输入的超时屏蔽Ctrl-C,终端驱动程序的模式,/*rotate.c*/#include#includeintmain()intc;while(c=getchar()!=EOF)if(c=z)c=aelseif(islower(c)c+;putchar(c);,规范模式:缓冲和编辑,使用默认设置运行该程序(-退格键)$gccrotate.c-orotate$./rotateabx-cdbcdeefgC$,输入的内容及程序所得到的内容,rotate程序,终端驱动程序,显示器及键盘,标准输入处理的特征,程序未得到输入的x,因为删除了它击键的同时字符显示在屏幕上,但直到按了回车,程序才接收到输入C键结束输入并终止程序程序rotate并不负责这些事情,对于输入的缓冲、回显、编辑和控制键处理都由驱动程序完成标准输入处理的这些特征被启动时,将终端连接称为规范模式,非规范处理,$stty-icanon;./rotateabbcxy?cddeeffggh$sttyicanonstty-icanon命令关闭驱动程序中的规范模式处理非规范模式没有缓冲,输入字母a,驱动程序跳过缓冲层,字符直接送到程序,然后程序显示字符b用户输入未缓冲可能会带来麻烦,如果用户想修改输入时,此时将无法修改,终端模式小结-规范模式,是用户常见的模式输入的字符保存在缓冲区接收到回车键时才将其中内容发送到程序缓冲功能使驱动程序可实现编辑功能,例如删除字符、单词或者行可通过命令stty或者系统调用tcsetattr修改执行上述操作的特定键,终端模式小结-非规范模式,缓冲和编辑功能被关闭时,连接被称为处于非规范模式设备驱动器仍然进行特定字符的处理,例如Ctrl-C及换行符及回车符之间的转换删除单词、字符及终止编辑键将不具有特殊含义而是被视作常规的数据输入,终端模式小结-raw模式,每个处理步骤都被一个独立的位控制,例如ISIG位控制Ctrl-C是否用于终止一个程序程序可随意关闭所有这些处理步骤当所有处理都被关闭后,驱动程序将输入直接传递给程序。这种模式就称为raw模式sttyraw命令,编写一个用户程序:play_again.c,play_again.c的逻辑:对用户显示提示问题接受输入如果是y返回0如果是n返回1第一个play_again0.c程序,play_again0.c的不足,必须先按回车,程序才能接受到数据当用户按回车键时,程序接收整行的数据对其进行处理,例如Doyouwantanothertransaction(y/n)?surething,surething,改进方法,首先关闭规范输入,使得程序能够在用户敲键的同时得到输入的字符set_crmode()structtermiosttystate;tcgetattr(0,/*installsettings*/,tty_mode(inthow),staticstructtermiosoriginal_mode;if(how=0)tcgetattr(0,程序的主要过程,首先调用tty_mode(0)函数保存当前终端的设置信息set_crmode()函数首先将终端置于一个字符接一个字符的模式然后调用函数显示一个提示符,并获得一个响应最后调用tty_mode(1)函数还原终端的设置,将终端置入字符输入模式包括两部分工作:将ICANON位关闭将控制字符数组中的VMIN下标元素置一,VMIN的值告诉驱动程序一次可以读取多少个字符,编译执行play_again1程序,此时,程序可以直接接收和处理字符而不用等待回车键但对每个非法字符都提示错误信息,可能比较烦可关闭回显模式,丢掉不需要的字符,直到得到可接收的字符为止在set_crmode函数中加入语句ttystate.c_lflagprintf(%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;,实验结果,在输入后,程序会延时一会儿如果长时间不输入,程序也会退出,fflush(out)函数,终端驱动对于输出也是一行行缓冲的直到它收到一个换行符或者程序试图从终端读取数据时才会进行输出而此时getchar被延迟读入,因此通过该函数将提示信息输出到屏幕上,否则用户将看不到提示信息。,Ctrl-C,执行上述程序时,如果输入Ctrl-C则程序终止运行,同时,也终止了整个登录会话原因是什么呢?,Ctrl-C,设置O_NDELAY设置crmode显示提示符等待用户输入用户输入恢复tty设置恢复fcntl标志退出,程序流程,CtrlC,进程被终止,进程正常退出时流向,Ctrl-C,程序接收到Ctrl-C后,会立即退出,此时,无法执行重置启动程序的代码返回shell并从用户获得命令行时,终端仍处于非阻塞模式。shell调用read获取命令行,但是因为处于非阻塞状态,read立即返回0.这时shell程序就退出原因总结:程序结束时,文件描述符处于一个错误的状态。,信号,Ctrl-C中断当前运行的程。这个中断由内核的信号机制产生Ctrl-C的过程:用户输入Ctrl-C驱动程序收到字符匹配VINTR和ISIG的字符被开启驱动程序调用信号系统信号系统发送SIGINT到进程进程收到SIGINT进程消亡,什么是信号,信号是由单个词组成的消息,例如红绿灯所发出的信息Ctrl-C时,内核向当前运行的进程发送中断信号每个信号都有一个数字编码。中断信号编码通常是2,信号的来源,信号来自内核生成信号的请求来自3个地方:用户-通过输入Ctrl-C、Ctrl-等请求内核产生信号内核-进程执行出错时,内核向进程发送一个信号,例如非法段访问、浮点数溢出等,也可通知进程特定事件的发生。进程-通过系统调用kill给另一个进程发送信号。进程之间可通过信号通信,同步与异步信号,由进程的某个操作产生的信号称为同步信号,例如被零除用户击键这样的进程外的事件引起的信号称为异步信号,信号列表,信号编号及其名字可在/usr/include/signal.h文件中找到,例如SIGINT为中断信号,SIGQUIT退出信号,SIGSEGV非法段访问信号可以使用信号消灭一个进程,也有办法保护自己不被杀死,进程处理信号的方法,进程通过signal系统调用告诉内核如何处理信号进程有3个选择:(1)接受默认处理SIGINT默认处理为消亡,进程通过系统调用signal(SIGINT,SIG_DFL)恢复默认处理(2)忽略信号signal(SIGINT,SIG_IGN)系统调用告诉内核忽略该信号,进程处理信号的方法,(3)调用一个函数,这是3种方法中最强大的一个。例如在play_again3程序中,当用户输入Ctrl-C时,程序收到信号后执行一个恢复设置的函数就不会发生上述情况了程序能够告诉内核,当信号来时调用哪个函数,signal(SIGINT,function);信号到来时所调用的函数称为信号处理函数,signal系统调用,signal系统调用,其中action可以是函数名也可以是如下两种特殊值之一:SIG_IGN,忽略信号SIG_DFL将信号恢复为默认处理signal返回前一个处理函数。值为指向该函数的指针,信号处理的例子sigdemo1.c,#include#includemain()voidf(int);/*declarethehandler*/inti;signal(SIGINT,f);/*installthehandler*/for(i=0;i5;i+)/*dosomethingelse*/printf(hellon);sleep(1);voidf(intsignum)/*thisfunctioniscalled*/printf(OUCH!n);,信号处理过程,main()signal(SIGINT,f);for(i=0;i5;i+)printf(“hellon”);sleep(1);,正常控制流,信号,函数f()printf(“OUCH”);,sigdemo1.c执行结果,hellohellohellohelloCOUCH!hello,忽略信号sigdemo2.c,#include#includemain()signal(SIGINT,SIG_IGN);printf(youcantstopme!n);while(1)sleep(1);printf(hahan);,sigdemo2.c程序执行结果,youcantstopme!hahahahaChahahahaChahahaha退出,sigdemo2.c调用signal忽略中断信号,可以随意按Ctrl-C而不会对程序产生影响,signal(SIGINT,SIG_IGNT),作业,6.10,处理多个信号,当有多个信号到达进程时,该如何处理?,1.捕鼠器问题,信号处理函数有点像捕鼠器早期版本中,在每次捕获之后,都必须重设它们。例如voidhandler(ints)signal(SIGINT,handler);,1.捕鼠器问题,即使设置的速度非常快,它还是需要时间触发处理函数及重新设置完成之前,有新的信号或者老鼠溜走这一脆弱的间隙使得原有的信号处理不可靠,因此称为不可靠的信号,处理多个信号,第二个信号打断第一个信号的处理第二个信号被阻塞返回信号处理的地方是否要重新开始?信号的优先级?,进程的多个信号,处理函数每次使用之后都要禁用吗?如果SIGY消息在进程处理SIGX消息时到达会发生什么?如果进程还在处理前一个SIGX时,第二个SIGX又到来会发生什么事情呢?第三个呢?如果信号到来时,程序正在处理getchar或者read之类的输入而阻塞,那会如何呢?,测试多个信号sigdemo3.c程序,signal(SIGINT,inthandler);/*sethandler*/signal(SIGQUIT,quithandler);/*sethandler*/doprintf(nTypeamessagen);nchars=read(0,input,(INPUTLEN-1);if(nchars=-1)perror(readreturnedanerror);elseinputnchars=0;printf(Youtyped:%s,input);while(strncmp(input,quit,4)!=0);,voidinthandler(ints)printf(Receivedsignal%d.waitingn,s);sleep(2);printf(Leavinginthandlern);voidquithandler(ints)printf(Receivedsignal%d.waitingn,s);sleep(3);printf(Leavingquithandlern);,执行结果,Typeamessagehelloyoutyped:helloTypeamessageCReceivedsignal3.Receivedsignal2.LeavinginthandlerLeavingquithandler,各种实验,(1)输入CCCC(2)CC(3)helloCReturn(4)helloReturnC(5)helloC,第一种情况,不可靠的信号若两个SIGINT信号杀死了进程,则系统是不可靠的信号若未杀死进程,则处理函数在被调用后还有作用现代信号处理机制允许在两者之间选择默认情况下,为后者第一次实验的结果为:信号函数执行了两次,后面的两次函数丢失,第二种情况:SIGY打断SIGX的处理函数,接连按下C和时程序先跳到inthandler,然后跳到quithandler,然后再回到inthandler,最后回到主循环第二种情况的实验:接收到后,程序进入quithandler程序,接收到C后,进入inthandler程序,最后返回到quithandler程序说明信号C打断信号,第三种情况:SIGX打断SIGX的处理函数,有三种可能:递归,调用同一个处理函数忽略第二个信号阻塞第二个信号直到第一个处理完毕第三种方法最好,,系统调用被中断,例如当调用read或者getchar函数时,程序接收到C的信号然后程序执行信号处理函数,执行完后,程序重新返回主循环程序是重新执行read还是从read返回同时设置errno为EINTR呢?,实验结果:,helloCReturn时,程序无法接收到hello输入helloReturnC时,程序可接收到hellohelCloReturn时,程序只接收到lohelloC时,无法得到hello输入,同时信号处理执行完后,重新开始read,信号机制其他的弱点,无法确定信号产生的原因-早期的模型只是告诉了信号的类型处理函数中无法安全阻塞其他消息voidinthandler(ints)intrv;void(*prev_qhandler)();prev_qhandler=signal(SIGQUIT,SIG_IGN);.signal(SIGQUIT,prev_qhandler);,无法同时调用inthandler以及忽略SIGQUIT无法阻塞SIGQUIT信号,sigaction可以处理多个信号,定制信号处理structsigaction,structsigactionvoid(*sa_handler)();void(*sa_sigaction)(int,siginfo_t*,void*);sigset_tsa_mask;intsa_flags;其中sa_handler可以为SIG_DFL,SIG_IGN或者函数名称,它是老的信号处理方式,sa_sigaction为新的信号处理机制它可获得信号编号及被调用的原因及产生问题的上下文的相关信息使用旧的处理机制:structsigactionaction;action.sa_handler=handler_old;使用新的处理机制:structsigactionaction;action.sa_sigaction=handler_new;将sigaction中的标志位sa_flags置为:SA_SIGINFO,sa_flags标志,sigaction的例子,structsigactionnewhandler;/*newsettings*/sigset_tblocked;/*setofblockedsigs*/voidinthandler();/*thehandler*/charxINPUTLEN;/*loadthesetwomembersfirst*/newhandler.sa_handler=inthandler;/*handlerfunction*/newhandler.sa_flags=SA_RESETHAND|SA_RESTART;/*options*/*thenbuildthelistofblockedsignals*/sigemptyset(,防止数据损毁,临界区修改一个数据结构的代码若在运行时被打断,将导致数据的不完整或损毁该代码称为临界区临界区不一定就在信号处理函数中保护它的最简单的办法就是忽略或阻塞处理函数将要使用或修改特定数据的信号,阻塞信号:sigprocmask和sigsetop,在信号处理一级或者进程一级阻塞信号在处理一个信号时阻塞另一个信号,设置structsigaction中的sa_mask成员位sa_mask指定哪些信号要被阻塞sa_mask类型为sigset_t,它定义了信号集合,进程的阻塞信号,任何时候进程都有一些信号被阻塞,这个信号的集合被称为信号挡板。系统调用sigprocmask可修改这个被阻塞的信号集sigprocmask是一个原子操作,根据所给的信号集来修改当前被阻塞的信号集,sigprocmask,how参数:SIG_BLOCK、SIG_UNBLOCK或者SIG_SETSIG_SET表示设置信号集合*sigs所指定的信号将被添加、删除或者替换之前的信号挡板设置将被复制到*prev中,sigsetops构造信号集,sigset_t是一个抽象的信号集通过函数添加或删除其中的信号sigemptyset(sigset_t*setp)清除由setp指向的列表中的所有信号sigfillset(sigset_t*setp)添加所有的信号到setp指向的列表中sigaddset(sigset_t*setp,intsignum)添加信号signum到setp指向的列表中sigdelset(sigset_t*setp,intsignum)从setp指向的列表中删除信号signum,阻塞用户信号的例子,sigset_tsigs,prevsigs;sigemptyset(sigprocmask(SIG_SET,*prevsigs,NULL);,重入代码,一个信号处理者或者一个函数,如果在激活状态下能被调用而不引起任何问题就称之为可重入的。sigaction时可以通过设置SA_NODEFER位允许处理函数的递归调用若处理函数是不可重入的,则必须阻塞信号若阻塞信号,则信号有可能丢失,kill从另一个进程发送信号,信号来自计时器、终端驱动、内核或者进程一进程可通过kill系统调用向另一个进程发送信号发送信号的进程的用户ID必须和目标进程的用户ID相同或者发送信号的进程拥有者是一个超级用户,kill系统调用,作业,7.12,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 课件教案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!