资源预览内容
第1页 / 共8页
第2页 / 共8页
第3页 / 共8页
第4页 / 共8页
第5页 / 共8页
第6页 / 共8页
第7页 / 共8页
第8页 / 共8页
亲,该文档总共8页全部预览完了,如果喜欢就下载吧!
资源描述
对话 UNIX:通过共享内存进展进程间通信从外表上看,UNIX 应用程序单独把握底层主机。它随时可以访问处理器,它的内存是神圣不行侵害的,连接它的设备只为它效劳。但是外表现象会骗人,这样有如君主一般确实定地 位 只是梦想而已。UNIX 系统同时运行大量应用程序,有限的物理资源要在它们之间共享。处理器力气被划分为时间片,应用程序映像常常被换入和换出真实内存,设备访问由需求驱 动,还 受到访问权限的限制。尽管您的 shell 提示符不断闪耀,但是 UNIX 系统并非只是等着您发出命令,在幕后有很多活动正在进展。常用缩略词 API:应用程序编程接口 IPv4:Internet 协议第 4 版 IPv6:Internet 协议第 6 版 POSIX:UNIX 的可移植操作系统接口尽管涉及一些简洁的机制,但是大多数应用程序不会留意到资源实际上是共享的,它们似乎 是独享资源。但是,可以编写相互交互的应用程序。例如, 一个应用程序收集或生成数据, 而另一个应用程序同时监视进度并分析信息。另一个例子是即时交换消息的谈天系统,其中 有两个对等的应用程序相互收发数据。 Secure Shell (ssh) 也是这样,它可以在两个完全不同的主机之间进展协作。在这些状况下,代码都要连接另一段独立的代码以交换信息,这 常常需要使用某种协议协商和把握交换过 程。UNIX 为实现这样的进程间通信 供给了多种技术。一些技术供给同一主机上的进程间通信, 其他技术可以实现主机到主机的信息交换。另外,各种技术的速度不同,所以必需选择最合 适自己需求的 技术。还必需进展协调实施时间把握和排他把握。例如,假设一个应用程序产生数据,另一个应用程序消费数据,那么当读完共享池时消费者必需停下来等待生 产者。另一方面,假设消费者无法足够快地读取池,生产者必需慢下来或暂停。表 1 总结在典型的 UNIX 系统上可用的进程间通信形式。表 1. UNIX 中的进程间通信名称说明范围用途在典型的 UNIX 文件中读写数据。任意数量的文件本地 共享大数据集进程都可以互操作。使用专用的文件描述符在两个进程之间传输数简洁的数据共享,比方生产者和管道本地据。通信只在父进程和子进程之间进展。消费者通过专用的文件描述符在进程之间交换数据。生产者和消费者或命令-把握,比命名通信可以在同一主机上的任意两个对等进程之本地 如 MySQL 和它的命令行查询工管道间进展。具无法在信号中传输数据,所以信信号 通过中断通知应用程序某一状况。本地号主要用于进程治理共享任何类型的协作,尤其适合需要通过在同一内存段中读写数据共享信息。本地内存安全性的状况套接 完成特别的设置过程之后,使用一般的输入/ 本地 FTP、ssh 和 Apache Web Server字输出操作传输数据。或远 等网络效劳程正如前面提到的,每种技术满足不同的需求。假设多个进程之间的协作的简洁性大体相当, 每种方法的优点和缺点如下: 通过一般的 UNIX 文件共享数据很简洁,由于它使用大家生疏的文件操作。但是, 通过文件系统共享数据很慢,由于磁盘输入和输出操作的效率远远比不上内存。另 外,只通过文件读 写数据很难协调。最终,在文件中保存敏感数据是担忧全的,由于根用户和拥有特权的其他用户可以访问这些信息。对于只读或只写的数据,适合 使用文件。 管道和命名管道也很简洁。它们在连接的两端使用两个标准的文件描述符 一个只执行读操作,另一个只执行写操作。但是,管道只能在父进程和子进程之间使用, 不能在任意两个进程之间使用。命名管道抑制了这个缺点,是在同一系统上 交换数据的好方法。但是,管道和命名管道都不供给随机访问,由于它们都作为先入先出(FIFO) 设备。 信号无法在进程之间传输数据。一般状况下,信号应当只用于在进程之间通知特别状况。 共享内存适合比较大的数据集,由于它使用内存,支持快速的随机访问。共享内存的实现有点儿简洁,尽管如此,对于多个进程之间的主机内 协作,共享内存是不错的方法。 套接字的功能与命名管道很相像,但是可以跨主机。本地套接字也称为 UNIX 套接字只能进展本地同一主机上的连接。Inet 和 Inet6 套接字分别使用 IPv4 和 IPv6 协议,它们承受远程连接也可以通过本地机器的 Internet 寻址机制承受本地连接。网络应用程序明显应中选择套接字,比方分布式处理或 web 扫瞄器。所需的代码比命名管道简洁一点儿,但是模式是固定的,在任何 UNIX 网络编程书中都有介绍。现在不考虑主机间 应用程序通信,看看如何通过共享内存在同一主机上进展进程间通信。回页首共享内存的工作方式顾名思义,共享内存让一段内存可供多个进程访问。用特别的系统调用即对 UNIX 内核的恳求安排和释放内存并设置权限;通过一般的读写操作读写内存段中的数据。共享内存并不是从某一进程拥有的内存中划分出来的;进程的内存总是私有的。共享内存是从系统的空闲内存池中安排的,期望访问它的每个进程连接它。这个连接过程称为映射,它给共享内存段安排每个进程的地址空间中的本地地址。图 1、图 2、图 3 和 图 4 说明此过程:1. 假设在同一系统上有两个进程 A 和 B 正在运行见 图 1,它们可以通过共享内存进展协作和共享信息。在图中 A 和 B 承受不同大小的图形,以此强调应用程序不必一样。图 1. 两个进程在同一个主机上运行,执行不同的代码2. 在 图 2 中,进程 A 恳求一个共享内存段。进程 A 对这个内存段进展初始化,让它预备好承受访问。这个过程还给内存段命名,让其他进程可以找到它。通常,内存段名称并不是动态安排的;而是众所周知的,比方使用头文件中的常量,其他代码可以便利地引用它。图 2. 一个进程恳求共享内存段3. 进程 A 把共享内存段连接即映射到自己的地址空间。进程 B 通过它的命名管道找到这个内存段,也把它映射到自己的地址空间,见图 3。两个进程扩大了,表示包含共享内存段。图 3. 两个进程连接即映射共享内存段4. 最终,在 图 4 中,进程 A 和 B 可以任凭读写共享内存段。依据与本地进程内存一样的方式对待共享内存。read 和 write 的作用与一般状况下一样。图 4. 两个或更多进程现在可以通过共同的内存共享数据这些图中所示的很多工作可以通过 UNIX 共享内存 API 执行。实际上,有两套共享内存API:POSIX API 和比较老但是照旧有效的 System V API。由于 POSIX 是 UNIX 和 Linux及其衍生系统上的公认标准,所以我们使用此版本。另外,POSIX API 使用简洁的文件描述符执行读写,大家应当更生疏。POSIX 为创立、映射、同步和取消共享内存段供给五个入口点: shm_open:创立共享内存段或连接到现有的已命名内存段。这个系统调用返回一个文件描述符。 shm_unlink:依据shm_open 返回的文件描述符,删除共享内存段。实际上, 这个内存段直到访问它的全部进程都退出时才会删除,这与在 UNIX 中删除文件很相像。但是,调用 shm_unlink 通常由原来创立共享内存段的进程调用之后, 其他进程就无法访问这个内存段了。 mmap:把共享内存段映射到进程的内存。这个系统调用需要 shm_open 返回的文件描述符,它返回指向内存的指针。在某些状况下,还可以把一般文件或另一个设备的文件描述符映射到内存。对这些操作的争论超出了本文的范围;具体方法请查阅操作系统的 mmap 文档。 munmap:作用与 mmap 相反。 msync:用来让共享内存段与文件系统同步 当把文件映射到内存时,这种技术有用。使用共享内存的过程是,用 shm_open 创立内存段,用 write 或 ftruncate 设置它的大小,用 mmap 把它映射到进程内存,执行其他参与者需要的操作。当使用完时,原来的进程调用 munmap 和 shm_unlink,然后退出。回页首例如应用程序清单 1 给出一个简洁的共享内存例如。代码取自 John Fusco 撰写的 The Linux Programmer”s Toolbox一书 由 Prentice Hall Professional 于 2023 年 3 月出版, ISBN 0132198576,已经得到出版商的使用授权。代码实现通过共享内存段通信的父进程和子进程。清单 1. 共享内存例如#include #include #include #include #include #include #include void error_and_die(const char *msg) perror(msg);exit(EXIT_FAILURE);int main(int argc, char *argv) int r;const char *memname = “sample“;const size_t region_size = sysconf(_SC_SIZE);int fd = shm_open(memname, O_CREAT | O_TRUNC | O_RDWR, 0666); if (fd = -1)error_and_die(“shm_open“);r = ftruncate(fd, region_size); if (r != 0)error_and_die(“ftruncate“);void *ptr = mmap(0, region_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (ptr = MAP_FAILED)error_and_die(“mmap“); close(fd);pid_t pid = fork; if (pid = 0) u_long *d = (u_long *) ptr;*d = 0xdbeebee; exit(0);else int status;waitpid(pid, &status, 0);printf(“child wrote %#lxn“, *(u_long *) ptr);r = munmap(ptr, region_size); if (r != 0)error_and_die(“munmap“);r = shm_unlink(memname); if (r != 0)error_and_die(“shm_unlink“);return 0;下面是代码中的一些要点:对 shm_open 的调用看起来应当很生疏;它与 open 函数很相像,包括初始化内存段和设置权限的方式。在这里,内存段是全局可读、全局可写的。假设调用成功,返回下一个未使用的文件描述符;否则,返回 -1 并相应地设置 errno。 ftruncate 把文件的大小设置为 region_size 字节,这以前设置
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号