您好,欢迎访问三七文档
进程间通信概述实现进程间通信(IPC)的方法很多,但从历史来看,很多都不可移植,经过多年的发展,已经有很大的统一IPC的方法主要包括:管道消息队列信号量共享内存套接字管道管道是最古老的IPC方式,在历史上,有两方面的限制:只能以半双工方式工作管道的两端必须是具有公共祖先的进程但最近的Unix系统大多都取消这两方面的限制,但为了兼容性原因,很多应用我们仍然假设管道只能以半双工方式工作无名管道和命名管道管道可以分为无名管道和命名管道两类无名管道没有名字,只能工作在具有同一个祖先进程的若干个进程中命名管道,又叫FIFO管道,可以在任何两个进程之间工作无名管道通过调用pipe系统调用可以创建一个无名管道intpipe(intfiledes[2]);由参数filedes返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开,filedes[1]的输出是filedes[0]的输入管道内核用户进程fd[0]fd[1]使用管道单个进程中管道基本没有什么用处调用pipe创建管道后,再调用fork,就创建了从父进程到子进程(或反向)的IPC通道还可以通过多次调用fork在两个子进程之间连接IPC通道管道的一方进程应该关闭自己不需要的管道描述符管道内核父进程fd[0]fd[1]子进程fd[0]fd[1]从子进程到父进程的管道管道内核父进程fd[0]子进程fd[1]两条规则当管道的一端被关闭后,下列两条规则起作用1.当读一个写端被关闭的管道时,所有数据被读取后,read返回0。(只要管道的写端还有进程,就不会产生文件结束)2.如果写一个读端被关闭的管道,则产生信号SIGPIPE,如果忽略或捕获该信号并返回,则write返回-1,errno设置为EPIPE一段典型的代码intmain(){intfd[2];pipe(fd);if((pid_tpid=fork())0){close(fd[0]);write(fd[1],....);......}else{close(fd[1]);read(fd[0],....);}}FIFO管道(命名管道)无名管道只能工作在具有同一个祖先进程的若干个进程中,FIFO管道可以克服这个问题FIFO管道是一种文件类型,可以被创建在文件系统中,并设置相应的权限多个进程可以通过分别以读/写方式打开该FIFO文件进行读/写,从而达到进行管道通信的目的intmkfifo(char*pathname,mode_tmode)FIFO管道的主要用途1.在进程之间传输数据,但不便于使用无名管道的地方2.在客户进程-服务器进程之间进行通信XSIIPC(XSI进程间通讯)有3种IPC被称为XSIIPC:消息队列、信号量和共享内存XSIIPC没有使用文件系统名字空间,而是构造了自己的名字空间这3种IPC具有类似的处理方式标识符和键每个内核中的IPC对象都用一个非负整数的标识符加以引用,它是IPC对象的内部名为了使多个合作进程能共享使用同一IPC对象,Unix使用了外部名:键。每个IPC对象都和一个键相关联可以调用ftok函数通过全局唯一字符串和项目ID产生键key_tftok(char*path,intid);XSIIPC结构IPC结构是在系统范围内起作用的,它不属于某一个进程IPC对象在文件系统中没有名字,只能使用专门的命令和函数访问这些对象,不能通过文件描述符来访问IPC相关的几个命令Unix系统提供了几个操纵IPC对象的命令ipcs:列出系统中的IPC对象ipcrm:删除指定的IPC对象一个例子------SharedMemorySegments--------keyshmidownerpermsbytesnattchstatus0x0052e6a90postgres6003820748840x0052e2c132769postgres600382074884------SemaphoreArrays--------keysemidownerpermsnsems0x0052e6a90postgres600170x0052e6aa32769postgres600170x0052e6ab65538postgres600170x0052e6ac98307postgres600170x0052e6ad131076postgres600170x0052e6ae163845postgres600170x0052e6af196614postgres600170x0052e2c1229383postgres600170x0052e2c2262152postgres600170x0052e2c3294921postgres600170x0052e2c4327690postgres600170x0052e2c5360459postgres600170x0052e2c6393228postgres600170x0052e2c7425997postgres60017------MessageQueues--------keymsqidownerpermsused-bytesmessages消息队列消息队列可以实现不同进程之间的消息传递消息队列组织成一个链接表消息的接收不一定按照先进先出的顺序,也可以按照消息的类型接收消息队列是可靠的、有流控的、面向对象的操纵消息队列先通过ftok取得键值key打开或创建消息队列intmsgget(key_tkey,intflag);发送消息intmsgsnd(intid,void*p,size_tnbytes,intflag);接收消息ssize_tmsgrcv(intid,void*p,size_tnbytes,longtype,intflag);信号量信号量是OS提供的一种重要的进程同步工具Unix信号量实现了整型信号量的一个超集功能。它是一组信号量,被称为信号量集,可以原子地对这组信号量集的若干个信号量一起进行操作信号量上的操作信号量的操作主要包括3个方面1.打开或创建信号量2.信号量值操作3.获取或者设置信号量属性打开/创建信号量和消息队列一样,先调用ftok获得键值key通过key打开或创建信号量,得到一个信号量集的标识intsemget(key_tkey,intnsems,intflag);信号量值操作信号量值的操作也就是wait(P)操作和signal(V)操作intsemop(intsemid,structsembufsemoparray[],size_tnops);其中sembuf结构表示了如何操作信号量的值semop具有原子性,要么执行所有的操作,要么什么也不做sembuf结构体structsembuf{unsignedshortsem_num;//信号量集中的编号shortsem_op;//信号操作shortsem_flg;//标志}sem_op为正表示增加信号量的值,为负表示减少信号量的值如果信号量的值不够减,进程被阻塞(无IPC_NOWAIT标志)共享内存共享存储允许两个或更多的进程共享一定的存储区这是最快的一种IPC需要进程自己解决访问同步问题获得共享存储标识和消息队列同样,先调用ftok获得键值key再调用shmget获得共享存储标识intshmget(key_tkey,size_tsize,intflag);将共享存储段连接到地址空间中共享存储段只有映射到进程的地址空间中才能被访问通过调用shmat可以将共享存储段连接到进程地址空间中void*shmat(intshmid,constvoid*addr,intflag);取消共享存储段在进程空间中的映射当使用完毕后,需要将共享存储段从进程地址空间中撤销intshmdt(void*addr);注意由于IPC对象是系统范围内的对象,不属于进程,所以,当进程结束的时候,系统不会帮进程清除相应的IPC对象,清理工作是进程的责任所以,如果可能,尽量避免使用IPC对象。比如,如果是简单情况,可以使用文件锁代替信号量。
本文标题:11_进程间通信
链接地址:https://www.777doc.com/doc-308258 .html