您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 第2章 进程管理4-进程通信
第2章进程管理本章主要内容进程的概念进程状态及转换进程控制及调度线程进程互斥与同步进程通信死锁进程通信进程通信低级通信:传递控制信号高级通信:传递数据软中断信号量共享存储区消息传递管道(文件)socket直接:消息缓冲队列间接:信箱在进程之间进行信息交换,包括传递信号和数据。请自行阅读教材P55-58关于进程通信的一般性介绍Linux进程s通信4软中断机制信号量机制(略)无名管道机制消息队列机制共享存储区机制Linux软中断通信5软中断是对硬件中断的一种模拟。发送软中断就是向接收进程的task_struct结构中的相应项发送一个信号。接收进程在收到软中断信号后,将按照事先的规定去执行一个软中断处理程序。软中断号发送后不会立即调相应处理程序,而是必须等到接收进程执行时才生效。进程也可以给自己发送软中断信号,以便在某些特殊情况下能转入规定好的处理程序。6Linux软中断信号Linux常见软中断信号类型,可以使用kill-l查看。7格式:signal(sig,function)sig—系统给定的软中断信号中的序号或名称function—与软中断信号关联的处理函数名,当进程在运行过程中捕捉到指定的软中断信号后,中断当前程序的执行转到该函数执行。注意:软中断信号必须提前预置,然后才可以在程序运行中捕获。软中断信号预置函数signal()8格式:intkill(pid,sig)pid—进程(组)标识符:当pid0时,将信号发给指定pid的进程;当pid=0时,将信号发给同组所有进程;当pid=-1时,将信号发给内存所有进程;当pid0时,将信号发给进程组识别码为|pid|的所有进程。sig—软中断信号的序号或名称功能:向指定进程发软中断信号sig头文件:sys/types.h,signal.h发送软中断信号函数kill9[例1]编一程序实现循环显示字符串“Hello!”,当键盘键入Ctrl+C时终止循环,显示“OK!”后结束。分析:Ctrl+C对应的软中断信号SIGINT(序号为2),对应处理函数需终止循环显示。软中断例1intk=1;voidmain(void){while(k==1)printf(Hello!\n);//等待键入Ctrl+Cprintf(“OK!\n”);}#includesignal.hvoidint_func(intsig)//软中断处理函数{k=0;}{signal(SIGINT,int_func);//预置软中断信号处理函数}10软中断例2[例2]使用软中断实现父子进程同步,父进程先输出A,然后子进程输出B。#includesignal.hintk=1;voidfunc(intsig){k=0;}main(){intpid;pid=fork();if(pid0){printf(A\n);kill(pid,12);}elseif(pid==0){signal(12,func);while(k==1)sleep(1);printf(B\n);}}非软中断方式main(){intpid;pid=fork();if(pid0){printf(A\n);wait(0);}elseif(pid==0){printf(B\n);}}Linux无名管道通信若只触发某些行为,软中断信号机制简捷有效。若进程间需交换数据?----管道管道:用“管道”将读写进程连接在一起,写进程将数据从写入端写入,读进程将数据从读出端读出。数据量大小是系统定义的最大缓冲区字节数。系统调用接口write(pipeID[1],buf_out,size)read(pipeID[0],buf_in,size)进程A地址空间进程B地址空间输出缓冲buf_out输入缓冲buf_in管道文件创建和使用无名管道的系统调用1.创建管道格式:intpipe(intfp[2]);返回:0---正确返回,-1----错误返回参数:fp[1]为写入端,fp[0]为读出端功能:创建一个无名管道fp,fp[1]用于写,fp[0]用于读。2.读写管道----借助文件机制格式:写管道write(fp[1],buf,size);读管道read(fp[0],buf,size);参数:buf为数据缓冲区;size为l读写长度。头文件:unistd.h管道通信示例1main(){intp1,fd[2];charoutpipe[50],inpipe[50]=“Thisisamessagefromchild.”;pipe(fd);p1=fork();if(p1==0)write(fd[1],inpipe,50);//写信息到管道elseif(p10);{wait(0);//等待子进程终止read(fd[0],outpipe,50);//从管道读信息printf(%s\n,outpipe);}}父进程创建一个子进程和一个无名管道fd,子进程向管道写入“Thisisamessagefromchild!”后终止;父进程接收到子进程终止信号后从管道中读出并显示信息后结束。管道通信示例2main(){intp1,fd[2];charstr1[50],str2[50];pipe(fd);p1=fork();子进程执行的分支父进程执行的分支}父进程创建一个子进程和一个无名管道fd,子进程通过管道向父进程发送“Howareyou?”,父进程接收到消息后通过管道回送“Iamfine.”,父子进程将各自收到的消息显示出来。elseif(p10){read(fd[0],str1,50);printf(“Parentreceived:%s\n”,str1);strcpy(str2,”Iamfine.”);write(fd[1],str2,strlen(str2));}if(p1==0){strcpy(str1,”Howareyou?”);write(fd[1],str1,strlen(str1));read(fd[0],str2,50);printf(“Childreceived:%s\n”,str2);}管道通信示例2执行结果分析父进程读不到数据被阻塞了子进程把自己写入管道的数据读出来了!修改管道通信示例2若将子进程执行分析修改为:if(p1==0){strcpy(str1,”Howareyou?”);write(fd[1],str1,strlen(str1));sleep(1);read(fd[0],str2,50);printf(“Childreceived:%s\n”,str2);}父进程不变:elseif(p10){read(fd[0],str1,50);printf(“Parentreceived:%s\n”,str1);strcpy(str2,”Iamfine.”);write(fd[1],str2,strlen(str2));}请分析上述代码执行结果:先调度到父进程?先调度到子进程?无名管道通信机制特点管道中的数据是字符流,工作于单向通信方式;管道逻辑上是由系统在内存中创建的临时文件实现的,物理上则由文件系统的高速缓冲区构成;无名管道只能供创建管道的进程及其子孙进程共享;管道为临界资源,各进程对管道的访问既有同步又有互斥,需要用户自己借助同步互斥机制以及文件机制来实现对管道的访问!Linux消息缓冲队列msg_queue链表----系统所有消息队列等待发送进程pid等待接收进程pid……msg_msg*nextmsg_msg*nextmsgbufmsgbuf……………………iker_ipc_permkey……q_messagesq_receiversq_sanders一个msg_queue结构对应一个消息队列msg结构消息队列有一个称为关键字(key)的名字;收发消息前必须创建消息队列,使用消息队列描述符(msqid)来标识该消息队列。Linux消息队列系统调用19intmsgget(key_tkey,intmsgflg);intmsgctl(intmsqid,intcmd,structmsqid_ds*buf);intmsgsnd(intmsqid,structmsgbuf*msgp,size_tmsgsz,intmsgflg);sszie_tmsgrcv(intmsqid,structmsgbuf*msgp,size_tmsgsz,longmsg_typ,intmsgflg);相关头文件:sys/types.h,sys/ipc.h,sys/msg.h,stdio.h1.创建或获取消息队列格式:intmsgget(key_tkey,intmsgflag);功能:创建或获取标识为key的消息队列,并返回队列描述符。返回:正确返回该消息队列的描述符msgid;错误返回-1。参数:key—消息队列标识符,为正整数。可由用户指定(适用于不同进程家族);也可使用IPC_PRIVATE由系统产生key值(适用于同一进程家族);msgflag—标志或访问方式,由操作权限和控制命令进行或运算得到。操作权限:用户可读0400小组可读0040其他可读0004用户可写0200小组可写0020其他可写0002控制命令:IPC_CREAT(值0001000),若队列不存在则创建。21/*有关头文件…..*/main(){intqid;key_tkey=113;qid=msgget(key,IPC_CREAT|0666);//创建消息队列if(qid0){perror(msgget);exit(1);}printf(createdqueueid:%d\n,qid);system(ipcs-q);//查看系统IPC的状态}创建消息队列示例2.对消息队列的控制格式:intmsgctl(intmsgid,intcmd,structmsqid_ds*buf);功能:查询、设置消息队列的状态;撤消消息队列。返回:函数调用成功返回0,不成功返回-1。参数:msgid—该消息队列的描述符;cmd—规定命令的类型:IPC_STAT查询消息队列状态,将消息队列的msqid_ds复制到buf;IPC_SET设置或修改消息队列状态,设置有效用户、组标识、操作允许权、字节数;IPC_RMID撤消描述符为msgid的消息队列;buf—含有控制参数或查询结果的用户缓冲区的地址,可为0。/*有关头文件…..*/main(){intqid;intkey=113;qid=msgget(key,IPC_CREAT|0666);//创建消息队列if(qid0){perror(msgget);exit(1);}printf(createdqueueid:%d\n,qid);system(“ipcs-q”);//查看系统IPC的状态if(msgctl(qid,IPC_RMID,NULL)0){perror(“msgctl”);exit(1);}system(ipcs-q);printf(successfullyremoved%dqueue\n,qid);}删除消息队列示例3.发送消息格式:intmsgsnd(intmsgid,structmsgbuf*msgp,intsize,intflag);功能:将msgp-msgbuf中的消息复制到msgid消息队列中,将之挂到队尾,唤醒等待消息的进程。参数:msgid—执行msgget()返回的消息队列的描述符;msgp—待发送的消息;size—由msgp指向的数据结构中消息长度;flag—规定当消息队列满时应执行的动作,例如:若在flag中设置了IPC_NOWAIT,则当消息队列中的字节数超过最大值时,msgsnd立即返回,否则msgsnd睡眠。flag可置0。25/*有关头文件…..*/structmsg{longmtype;//消息类型charmtext[511];//消息正文};intmain(void){intqid,pid;structmsgpmsg;//创建消息队列qid=
本文标题:第2章 进程管理4-进程通信
链接地址:https://www.777doc.com/doc-3418999 .html