进程控制与进程间通信.ppt
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 进程 控制 通信
- 资源描述:
-
单击以编辑母版标题样式,单击以编辑母版文本样式,第二级,第三级,第四级,第7章 第,*,页,第7章 进程控制与进程间通信,1,7.1 进程控制,2,进程与程序,程序,指令和数据的集合,存放在磁盘上的一个普通文件里,文件的i节点中标为可执行,内容符合系统要求,进程,包括指令段、用户数据段和系统数据段的执行环境,进程和程序的关系,程序用于初始化进程的指令段和用户数据段,初始化后,进程和初始化它的程序之间无联系,进程运行时磁盘上的程序文件不可修改/删除,同时运行的多个进程可由同一程序初始化得到,进程之间没什么联系。核心通过安排它们共享指令段以节省内存,但这种安排对用户来说是透明的,3,进程的组成部分(1),四部分:指令段,数据段,堆栈段和系统数据,指令段(Text),程序的CPU指令代码,包括:主程序和子程序编译后的CPU指令代码,以及调用的库函数代码,指令段的大小固定不变,只读,用户数据段,全局变量,静态(static)变量,字符串常数,允许数据段增长和缩小,实现内存的动态分配,系统调用sbrk()允许编程调整数据段的大小,内存管理库函数,如:malloc(),free(),4,进程的组成部分(2),用户堆栈段,程序执行所需要的堆栈空间,实现函数的调用,用于保存子程序返回地址,在函数和被调函数之间传递参数,函数体内部定义的变量(静态变量除外),main函数得到的命令行参数以及环境参数,存放在堆栈的最底部,main函数运行之前,这些部分就已经被系统初始化,堆栈段的动态增长与增长限制,系统数据段,上述三部分在进程私有的独立的逻辑地址空间内,系统数据段是内核内的数据,每个进程对应一套,包括页表和进程控制块,PCB,5,进程逻辑地址空间的布局,6,进程的系统数据,在UNIX内核中,含有进程的属性,包括:,页表,进程状态,优先级信息,核心堆栈,当前目录(记录了当前目录的i-节点),根目录,打开的文件描述符表,umask值,进程,PID,PPID,进程主的实际UID/GID,有效UID/GID,进程组组号,7,user结构和proc结构,进程PCB被分为user结构和proc结构两部分,user结构,(约5000字节),,进程运行时才需要的数据在user结构,核心态堆栈占用了较多空间,proc,结构(约300字节),,,进程不运行时也需要的管理信息存于proc结构,用户程序不能直接存取和修改进程的系统数据,系统调用可用来访问或修改这些属性,chdir,umask,open,close,setpgrp,getpid,getppid,8,进程的基本状态,基本状态,进程创建之后,主要有运行状态和睡眠状态(也叫阻塞状态,等待状态,挂起状态,等等),内核总是在分时处理运行状态的进程,而不顾那些处于睡眠状态的进程,睡眠状态的进程,在条件满足后转化为运行状态,进程在睡眠时,不占用CPU时间,注意:在编程时,程序不要处于忙等待状态,9,进程的调度,调度优先级,内核将可运行进程按优先级调度,高优先级进程优先,进程的优先级总在不停地发生变化,处于睡眠状态的进程一旦被叫醒后,被赋以高优先级,以保证人机会话操作和其它外设的响应速度,用户程序用nice()系统调用有限地调整进程的优先级,10,scanf(%d,程序在串口终端上执行时操作员输入756然后按下回车,11,time:进程执行的时间,进程执行时间包括,睡眠,时间,CPU时间(用户时间和系统时间),外部命令/usr/bin/time,B-shell和C-shell都有个内部,命令time,/usr/bin/time find/usr-name*.c-print,Real 6.06,User 0.36,System 2.13,C-shell,:,time find/usr-name*.h-print,0.4u 6.2s 0:10 61%4+28k 0+0io 0pf+0w,与CPU时间有关的命令vmstat,$,vmstat 10,procs memory swap io system cpu,r b w swpd free buff cache si so bi bo in cs us sy id,0 0 0 0 55916 6128 38156 0 0 439 118 146 180 8 15 76,0 0 0 0 55252 6160 38160 0 0 0 32 112 54 26 1 73,12,系统调用times(),系统调用times(),当前,进程CPU时间,已结束子进程占用过的CPU时间,clock_t times(struct tms*buf);,struct tms,clock_t tms_utime;/*user CPU time*/,clock_t tms_stime;/*system CPU time*/,clock_t tms_cutime;/*user CPU time,terminated children*/,clock_t tms_cstime;/*system CPU time,terminated children*/,;,clock(),返回times()的,四个CPU时间,的总和。单位是1/CLOCKS_PER_SEC秒,getrusage()函数,times()函数的升级版本,返回CPU时间,,还返回表示资源使用状况的另外14个值,包括内存使用情况,,I/O次数,,进程切换次数,13,与时间有关的函数,标准函数库中time():获得当前时间坐标,坐标,0为1970年1月1日零点,,单位:秒,t=time(0);和time(都会使t值为当前时间坐标,函数gettimeofday(),获得当前时间坐标,,坐标的0是1970年1月1日零点,可以精确到,微秒,s,(10,-6,秒),localtime(),将坐标值转换为本地时区的年月日时分秒,mktime,将年月日时分秒转换为坐标值,ctime()和asctime(),坐标值和年月日时分秒转换为可读字符串,14,忙等待,多任务系统中“忙等待”的程序是不可取的,1#include,2 main(int argc,char*argv),3,4 unsigned char buf1024;,5 int len,fd;,6 if(fd=open(argv1,O_RDONLY)0),13 write(1,buf,len);,14 ,15,程序14行前增加sleep(1):1秒定时轮询,select()调用可将睡眠时间设为10毫秒级精度,15,fork:创建新进程,功能,fork系统调用是创建新进程的唯一方式,原先的进程,称做“父进程”,,新创建进程被称作,“子进程”,完全复制:新进程的指令,用户数据段,堆栈段,部分复制:系统数据段,fork返回值:父子进程都收到返回值,但不相同,返回值很关键,它,用于区分父进程(返回值0,是子进程的PID)和子进程(返回值=0),失败时返回-1,内核实现,创建新,的proc结构,复制父进程环境(包括user结构和内存资源)给子进程,父子进程可以共享程序和数据(例如:copy-on-write技术),但是系统核心的这些安排,对程序员透明,16,fork举例(1),执行结果,1./fork1:BEGIN,2 a+b=30,3 a+b=230,4./fork1:END,3 a+b=230,4./fork1:END,int a;,int main(int argc,char*argv),int b;,printf(1%s:BEGINn,argv0);,a=10;,b=20;,printf(2 a+b=%dn,a+b);,fork();,a+=100;,b+=100;,printf(3 a+b=%dn,a+b);,printf(4%s:ENDn,argv0);,17,fork举例(2),执行结果,Hello,pid=815 ppid=814,a=6,Bye,Pid=814 child=815,a=6,Bye,main(),int a,pid;,printf(Hellon);,a=3;,pid=fork();,a+=3;,if(pid 0),printf(Pid=%d child=%d,a=%dn,getpid(),pid,a);,else if(pid=0),printf(pid=%d ppid=%d,a=%dn,getpid(),getppid(),a);,else,perror(Create new process);,printf(Byen);,18,命令ps,功能,查阅进程状态(process status)(实际上就是将内核中proc和user数组的内容有选择地打印出来),选项,用于控制列表的行数(进程范围)和列数(每进程列出的属性内容),无选项:只列出在当前终端上启动的进程,列出的项目有:PID,TTY,TIME,COMMAND,e,选项:列出系统中所有的进程,(进程范围),t,选项:列出指定终端上的所有进程,(进程范围),f,选项:以full格式列出每一个进程,(控制列的数目),l,选项:以long格式列出每一个进程,(控制列的数目),19,命令ps举例,例:ps-ef命令的输出,UID PID PPID C STIME TTY TIME COMMAND,root 0 0 0 16:11:14?0:00 sched,root 1 0 0 16:11:14?0:01/etc/init,root 2 0 0 16:11:14?0:00 vhand,root 3 0 0 16:11:14?0:00 bdflush,root 6547 335 0 16:15:05 01 0:00 server 4 1,root 175 1 0 16:11:14?0:00 inetd,root 173 1 0 16:11:14?0:00 syslogd,root 296 1 0 16:11:21?0:00/tcb/files/no_luid/sdd,root 6551 291 80 16:17:16 08 0:37 busy_check,root 335 1 0 16:11:31 01 0:00 server_ctl,root 337 1 0 16:11:33 01 0:05 server_ap,root 353 1 0 16:12:01 12 0:00 client_ctl 100.1.1.3,root 356 295 0 16:12:07 12 0:04 client_ap 1403,20,命令ps列出的进程属性,UID,:,用户ID(注册名),PID,:,进程ID,C,:,CPU占用指数:最近一段时间(秒级别)进程占用CPU情况。不同系统算法不同,例如:正占CPU进程10ms加1,所有进程1秒衰减一半,PPID,:父,进程的PID,STIME,:启动时间,SZ,:进程逻辑内存大小,(Size),TTY,:终端的名字,COMMAND,:命令名,WCHAN,:进程,睡眠通道(Wait Channel),TIME,:累计,执行时间(占用CPU的时间),PRI,:优先级,S,:状态,S,(Sleep),,R,(Run),,Z,(Zombie),21,访问环境参数的三种方法,main(),extern char *environ;,char*p;,p=environ;,while(*p)printf(”%sn”,*p+);,main(int argc,char*argv,char*env),char*p;,p=env;,while(*p)printf(”%sn”,*p+);,main(),char*p;,p=getenv(”HOME”);,if(p)printf(”%sn”);,22,exec系统调用,功能,用一个指定的程序文件,重新初始化一个进程,可指定新的命令行参数和,环境参数(初始化堆栈底部),exec不创建新进程,,只是将当前进程重新初始化了指令段和用户数据段,堆栈段以及CPU的PC指针,6种格式exec系统调用,exec前缀,后跟一至两个字母,l,list,,,v,vector,,,e,env,,,p,path,l,与,v,:指定命令行参数的两种方式,,l,以表的形式,,v,要事先组织成一个指针数组,e,:需要指定envp来初始化进程。,p,:使用环境,变量PATH查找,可执行文件,六种格式的区别:不同的参数方式初始化堆栈底部,23,exec系统调用格式,int execl(char*,file,,char*,arg0,,char*,arg1,,.,0);,int execv(char*,file,char*,argv,);,int execle(char*,file,char*,arg0,char*,arg1,.,0,char*,envp,);,int execve(char*,file,char*,argv,char*,envp,);,int execlp(char*,file,char*,arg0,char*,arg1,.,0);,int execvp(char*,file,char*,argv,);,24,重点掌握execlp execvp,execlp:知道具体的命令的格式,规定好了,execvp:把要执行的命令方法数组里(vecter)你们知道吗!,execlp(“ls”,”ls”,”-l”,”fork2.c”,0),char*abc=“ls”,*bb3=“ls”,”-l”,”fork2.c”,execvp(abc,bb),就行了,参见书中186页的例子,25,“僵尸”进程,“僵尸”进程(zombie或defunct),进程生命期结束时的特殊状态,系统已经释放了进程占用的包括内存在内的系统资源,但仍在内核中保留进程的部分数据结构,记录进程的终止状态,等待父进程来,“收尸”,父进程的“收尸”动作完成之后,“僵尸”进程不再存在,僵尸进程占用资源很少,仅占用内核进程表资源,过多的僵尸进程会导致系统有限数目的进程表被用光,孤儿进程,26,wait系统调用,功能,等待进程的子进程终止,如果已经有子进程终止,则立即返回,函数原型,#include,#include,pid_t wait(int*,stat_loc,);,函数返回值为已终止的子进程PID,例,int status,pid;,pid=wait(,status中含有子进程终止的原因,TERMSIG(status)为被杀信号,EXITSTATUS(status)为退出码,waitpid()和wait3():wait系统调用的升级版本,27,字符串库函数strtok,char*strtok(char*,str,char*,tokens,),功能:返回第一个单词的首字节指针,28,最简单的shell:xsh0,main(),char buf256,*cmd,*argv100;,int n,sv;,for(;),printf(=);,if(fgets(buf,sizeof(buf),stdin)=NULL)exit(0);,cmd=strtok(buf,tn);,if(cmd!=NULL)continue;,if(strcmp(cmd,exit)=0)exit(0);,n=0;,argvn+=cmd;,while(argvn+=strtok(NULL,tn);,if(fork()=0),execvp(cmd,argv);,fprintf(stderr,*Bad commandn);,exit(1);,wait(,29,执行xsh0,=,=,who am i,root ttyp0 Nov 29 09:56,=,ps-f,UID PID PPID C STIME TTY TIME CMD,root 1012 1011 0 09:56:00 ttyp0 00:00:00 login-c-p,root 1020 1012 0 09:56:14 ttyp0 00:00:00-csh,root 1060 1020 2 10:36:37 ttyp0 00:00:00 xsh0,root 1062 1060 4 10:36:46 ttyp0 00:00:00 ps-f,=,ls-l*.c,ls:*.c not found:No such file or directory(error 2),=,mmx,*Bad command,=,ls-l xsh0,-rwxr-r-1 root other 43417 Dec 1 1998 xsh0,=,exit,30,system:运行一个命令,int system(char*,string,);,库函数system执行用字符串传递的shell命令,可使用管道符和重定向,库函数system()是利用系统调用fork,exec,wait实现的,31,system应用举例,#include,main(),char fname256,cmd256,buf256;,FILE*f;,tmpnam(fname);,sprintf(cmd,netstat-rn%s,fname);,printf(Execute%sn,cmd);,system(cmd);,f=fopen(fname,r);,while(fgets(buf,sizeof buf,f),printf(%s,buf);,fclose(f);,printf(Remove file%sn,fname);,unlink(fname);,32,7.2 进程与文件描述符,33,活动文件目录AFD,磁盘文件目录(分两级),文件名,i节点,活动文件目录(分三级),文件描述符表FDT:每进程一张,user结构中,user结构中整型数组u_ofile记录进程打开的文件,文件描述符fd是u_ofile数组的下标,系统文件表SFT:整个核心一张,file结构,struct file,char f_flag;/*读、写操作要求*/,char f_count;/*引用计数*/,int f_inode;/*内核中inode数组的下标*/,long f_offset2;/*文件读/写位置指针*/,;,活动i节点表:整个核心一张,inode结构,内存中inode表是外存中inode的缓冲,34,活动文件目录AFD(图),35,文件描述符的继承与关闭,fork创建的子进程继承父进程的文件描述符表,父进程在fork前打开的文件,父子进程有相同的文件偏移,fork前,fork后,36,例:文件描述符的继承与关闭(1),#include,void main(),int fd;,static char*str=F1:ABCDn;,fd=open(abc,O_CREAT|O_WRONLY,0666);,write(fd,str,strlen(str);,if(fork()0),write(fd,str,strlen(str);,close(fd);,else,char fdstr16;,sprintf(fdstr,%d,fd);,execlp(f2,f2,fdstr,0);,printf(failed to start f2n);,exit(0);,37,例:文件描述符的继承与关闭(2),文件,f2.c,int,main(int,argc,char*,argv,),int,fd,;,static char*,str,=F2:WXYZn;,fd,=strtol(argv1,0,0);,write(fd,str,strlen(str,);,close(fd,);,38,close-on-exec标志,文件close-on-exec标志,文件描述符fd设置了close-on-exec标志,执行exec系统调用时,系统会自动关闭这些文件,函数,#include ,int fcntl(,fd,cmd,arg,);,cmd,:F_GETFD 获取文件,fd,的控制字,控制字的比特0(FD_CLOEXEC):close-on-exec标志位,flag=fcntl(fd,F_GETFD,0);,cmd,:F_SETFD 设置文件,fd,的控制字,fcntl(fd,F_SETFD,flag);,例,flags=fcntl(fd,F_GETFD,0);,flags|=FD_CLOEXEC;,fcntl(fd,F_SETFD,flags);,39,文件描述符的复制,系统调用,int dup2(int,fd1,int,fd2,);,功能,复制文件描述符,fd1,到,fd2,fd2,可以是空闲的文件描述符,如果,fd2,是已打开文件,则关闭已打开文件,40,xsh1:输入输出重定向(1),char buf256,*cmd,*argv100,*infile,*outfile;,int n,sv;,for(;),printf(=);,if(fgets(buf,sizeof(buf),stdin)=NULL)exit(0);,infile=strstr(buf,);,if(infile),*infile=0;,infile=strtok(infile+1,tn);,if(outfile),*outfile=0;,outfile=strtok(outfile+1,tn);,cmd=strtok(buf,tn);,if(cmd=NULL)continue;,if(strcmp(cmd,exit)=0)exit(0);,n=0;,argvn+=cmd;,while(argvn+=strtok(NULL,tn);,41,xsh1:输入输出重定向(2),if(fork()=0),int fd0=-1,fd1=-1;,if(infile!=NULL),fd0=open(infile,O_RDONLY);,if(outfile!=NULL),fd1=open(outfile,O_CREAT|O_WRONLY,0666);,if(fd0!=-1),dup2(fd0,0);,if(fd1!=-1),dup2(fd1,1);,close(fd0);,close(fd1);,execvp(cmd,argv);,fprintf(stderr,*Bad commandn);,exit(1);,wait(,42,管道操作(1),创建管道,int pipe(int,pfd,2),创建一个管道,,pfd,0和,pfd,1分别为管道两端的文件描述字,,pfd,0用于读,,pfd,1用于写,管道写,ret=write(pfd1,buf,n),若管道已满,则被阻塞,直到管道另一端read将已进入管道的数据取走为止,管道容量:某一有限值,如8192字节,43,管道操作(2),管道读,ret=read(pfd0,buf,n),若管道写端已关闭,则返回0,若管道为空,且写端文件描述字未关闭,则被阻塞,若管道不为空(设管道中实际有m个字节),nm,则读m个;,如果nm则读取n个,实际读取的数目作为read的返回值。,注意:管道是无记录边界的字节流通信,关闭管道close,关闭写端则读端read调用返回0。,关闭读端则写端write导致进程收到SIGPIPE信号(默认处理是终止进程,该信号可以被捕捉),写端write调用返回-1,errno被设为EPIPE,44,父子进程管道通信,父进程,fork后,父进程关闭读端,子进程关闭写端,45,管道通信:写端,/*File name:pwrite.c */,#define syserr(str)perror(str);exit(1);,main(),int pfd2;,char fdstr10,*message=Send/Receive data using pipe;,if(pipe(pfd)=-1)syserr(Create pipe);,switch(fork(),case-1:,syserr(fork);,case 0:/*child*/,close(pfd1);,sprintf(fdstr,%d,pfd0);,execlp(./pread,pread,fdstr,0);,syserr(Execute pread file);,break;,default:/*parent*/,close(pfd0);,if(write(pfd1,message,strlen(message)+1)=-1),perror(Write pipe);,break;,46,管道通信:读端,/*File name:pread.c*/,#define syserr(str)perror(str);exit(1);,main(int argc,char*argv),int fd,nbyte,i;,char buf1024;,fd=strtol(argv1,0,0);,nbyte=read(fd,buf,sizeof(buf);,switch(nbyte),case-1:,syserr(Read pipe);,break;,case 0:,printf(Pipe closedn);,break;,default:,printf(%d bytes%sn,nbyte,buf);,break;,exit(0);,47,管道通信:应注意的问题,管道传输是一个无记录边界的字节流,写端一次write所发数据读端可能需多次read才能读取,写端多次write所发数据读端可能一次read就全部读出,父子进程需要双向通信时,应采用两个管道,用一个管道,进程可能会收到自己刚写到管道去的数据,增加其他同步方式太复杂,父子进程使用两个管道传递数据,有可能死锁,父进程因输出管道满而写,导致被阻塞,子进程因要向父进程写回足够多的数据而导致写也被阻塞,这时死锁发生,多进程通信问题必须仔细分析流量控制和死锁问题,管道的缺点:没有记录边界,48,命名管道,pipe创建的管道的缺点,只限于同祖先进程间通信,命名管道,允许不相干的进程(没有共同的祖先)访问FIFO管道,命名管道的创建,用命令 mknod pipe0 p,创建一个文件,名字为pipe0,用ls-1列出时,文件类型为p,发送者,fd=open(”pipe0”,O_WRONLY);,write(fd,buf,len);,接收者,fd=open(”pipe0”,O_RDONLY);,read(fd,buf,sizeof(buf);,49,xsh2:管道(1),main(),char buf256,*buf2,*cmd,*cmd2,*argv64,*argv264;,int n,sv,fd2;,for(;),printf(=);,if(fgets(buf,sizeof(buf),stdin)=NULL)exit(0);,buf2=strstr(buf,|);,if(!buf2)exit(0);,*buf2+=0;,cmd=strtok(buf,tn);,if(!cmd)exit(1);,n=0;,argvn+=cmd;,while(argvn+=strtok(NULL,tn);,cmd2=strtok(buf2,tn);,if(!cmd2)exit(1);,n=0;,argv2n+=cmd2;,while(argv2n+=strtok(NULL,tn);,50,xsh2:管道(2),pipe(fd);,if(fork()=0),dup2(fd0,0);,close(fd0);close(fd1);,execvp(cmd2,argv2);,fprintf(stderr,*bad commandn);,exit(1);,else if(fork()=0),dup2(fd1,1);,close(fd0);,close(fd1);,execvp(cmd,argv);,fprintf(stderr,*bad commandn);,exit(1);,close(fd0);,close(fd1);,wait(,wait(,51,int n,sv,fd2;,#define SC_KEY 0 x1111,允许不相干的进程(没有共同的祖先)访问FIFO管道,printf(”Input your choice:”);,rlen=msgrcv(qid,for(;),子进程终止,僵尸进程(defunct或zombie)出现,父进程使用wait系统调用收尸后消除僵尸,sprintf(cmd,netstat-rn%s,fname);,函数体内部定义的变量(静态变量除外),for(;)sleep(500);,fd=strtol(argv1,0,0);,用户在输入了命令A后反悔,希望中止func_a()对命令A的处理,而要重新选择另一条命令,n=0;,p=getenv(”HOME”);,#include sys/types.,7.3 信号,52,第二次上机作业,使用fork(),exec(),dup2(),pipe(),open()系统调用完成与下列shell命令等价的功能。,gr,ep v usr result.txt,53,命令kill,用法与功能,kill,signal,PID-list,kill命令用于向进程发送一个信号,举例,kill 1275,向进程1275的进程发送信号,默认信号为15(SIGTERM),一般会导致进程死亡,kill-9 1326,向进程1326发送信号9(SIGKILL),导致进程死亡,54,进程组,进程组,进程在其,proc结构中有p_pgrp,域,p_pgrp都相同,的进程构成,一个“进程组”,如果,p_pgrp=p_pid则,该进程是组长,setsid()系统调用将,proc中的p_pgrp,改为进程自己的,PID,,从而脱离原进程组,成为新进程组的组长,fork创建的进程继承父进程,p_pgrp,,与父进程同组,举例,kill命令的PID为0时,向与本进程同组的所有进程发送信号,55,信号机制,功能,信号是送到,进程的“软件中断”,,通知进程出现了非正常事件,信号的产生,进程自己或者其他进程发出的,使用kill()或者alarm()调用,核心产生信号,段违例信号SIGSEGV:当进程试图存取它的地址空间以外的存贮单元时,内核向进程发送段违例信号,浮点溢出信号SIGFPE:零做除数时,内核向进程发送浮点溢出信号,信号SIGPIPE:关闭管道读端则写端write导致进程收到信号SIGPIPE,56,信号类型,在文件中定义宏,SIGTERM 软件终止信号。用kill命令时产生,SIGHUP 挂断。当从注册,shell中,logout时,,同一进程组的所有进程都收到SIGHUP,SIGINT 中断。用户按,Del键或Ctrl-C键,时产生,SIGQUIT 退出。按,Ctrl-时产生,,产生core文件,SIGALRM 闹钟信号。计时器时间到,与alarm()有关,SIGCLD 进程的一个子进程终止。,SIGKILL 无条件终止,该信号不能被捕获或忽略。,SIGUSR1,SIGUSR2 用户定义的信号,SIGFPE 浮点溢出,SIGILL 非法指令,SIGSEGV 段违例,57,#include 0:返回类型为mtype的第一个消息,root 335 1 0 16:11:31 01 0:00 server_ctl,用户在输入了命令A后反悔,希望中止func_a()对命令A的处理,而要重新选择另一条命令,进程逻辑地址空间的布局,文件描述符fd设置了close-on-exec标志,执行exec系统调用时,系统会自动关闭这些文件,指令段的大小固定不变,只读,#include 0时,向指定的进程发信号,当pid=0时,向与本进程同组的所有进程发信号,当pid0时,将时钟设置成,secs,指定的秒数,当,secs,=0时,关闭报警时钟。,65,alarm系统调用举例,#include,char cmd100;,default_cmd(int sig),printf(CMD_An);,strcpy(cmd,CMD_A);,main(),signal(SIGALRM,default_cmd);,alarm(5);,printf(Input command:);,scanf(%s,cmd);,alarm(0);,printf(cmd=%sn,cmd);,.,.,66,全局跳转(1),main(),int c;,for(;),printf(”Input a command:”);,c=getchar();,switch(c),case Q:return(0);break;,case A:func_a();break;,case B:func_b();break;,.,.,.,问题,用户在输入了命令A后反悔,希望中止func_a()对命令A的处理,而要重新选择另一条命令,67,全局跳转(2),#include,void main_control(int sig),int c;,signal(SIGINT,main_control);,for(;),printf(”Input your choice:”);,scanf(”%d”,switch(c),case 0:return;break;,case 1:func_1();break;,case 2:func_2();break;,.,.,main(),main_control();,68,全局跳转(3),上述程序存在的问题,每次按下中断键,程序停留在信号捕捉函数中,堆栈没有清理,嵌套越来越深浪费越来越大,main_control()一旦返回,进程的执行将弹回到刚才被SIGINT中断的地方恢复刚才的执行,会让用户感到迷惑不解,刚才的动作已打断而且又已经开始了新的工作,可过一段时间后又开始运行,C语言中的goto语句只限于一个函数体内使用,不能解决上述的问题,69,全局跳转(4),解决方法,把栈恢复为第一次调用main_control()时的状态,再调用main_control()去重新执行,有两个标准的子例程用于这个目的,#include,int setjmp(jmp_buf,jmpenv,);,/*返回值为零,或者是longjmp提供的,val,*/,void longjmp(jmp_buf,jmpenv,int,val,),/*,val,是提供给setjmp作返回值*/,70,全局跳转(5),#include ,#include,static jmp_buf jmpbuf;,void intr_proc(int sig),printf(”n.INTERRUPTED by signal%dn”,sig),longjmp(jmpbuf,1);,main(),int c;,setjmp(jmpbuf);,signal(SIGINT,intr_proc);,for(;),printf(”Input a command:”);,scanf(“%d”,switch(c),case 0:return;break;,case 1:func_1();break;,case 2:func_2();break;,71,7.4 消息队列,72,消息队列的创建,系统调用msgget,#include,#include,#include,int msgget(key_t,key,int,flags,);,在内核中创建新消息队列或获取已存在消息队列,的ID,,,发送/接收,消息的系统调用使用qid,(qid是内核中msqid_ds数组的下标),创建消息队列,qid=msgget(462101,IPC_CREAT|0666);,取得一个已存在的消息队列,qid=msgget(462101,0);,73,消息队列的系统数据结构,内核中每个消息队列对应一个msqid_ds结构,struct msqid_ds /*msg ID data structure*/,struct ipc_perm msg_perm;,/*operation permission struct*/,struct msg *msg_first;,/*ptr to first message on q*展开阅读全文

咨信网声明:本文档由用户上传并分享,仅供学习交流、研究之用,未经授权,严禁复制、发行、汇编、翻译或网络传播等,侵权必究。
咨信网小贴示:
1、浏览或下载可查看了解,请点击【咨信网告知】。
2、下载文件中如有侵权或不适当内容,将立即纠正。
3、如果因为网速或其他原因下载失败请重新下载,重复下载[60天内]不扣币。
4、开具发票登录电脑端申请,请点击【索取发票】。
咨信网客服组:【微信客服】
1、浏览或下载可查看了解,请点击【咨信网告知】。
2、下载文件中如有侵权或不适当内容,将立即纠正。
3、如果因为网速或其他原因下载失败请重新下载,重复下载[60天内]不扣币。
4、开具发票登录电脑端申请,请点击【索取发票】。
咨信网客服组:【微信客服】


进程控制与进程间通信.ppt
















自信AI助手














微信客服
客服QQ
发送邮件
意见反馈



链接地址:https://www.zixin.com.cn/doc/14521585.html