对话 UNIX 通过共享内存进行进程间通信.docx

上传人:b****5 文档编号:4168924 上传时间:2022-11-28 格式:DOCX 页数:9 大小:42.75KB
下载 相关 举报
对话 UNIX 通过共享内存进行进程间通信.docx_第1页
第1页 / 共9页
对话 UNIX 通过共享内存进行进程间通信.docx_第2页
第2页 / 共9页
对话 UNIX 通过共享内存进行进程间通信.docx_第3页
第3页 / 共9页
对话 UNIX 通过共享内存进行进程间通信.docx_第4页
第4页 / 共9页
对话 UNIX 通过共享内存进行进程间通信.docx_第5页
第5页 / 共9页
点击查看更多>>
下载资源
资源描述

对话 UNIX 通过共享内存进行进程间通信.docx

《对话 UNIX 通过共享内存进行进程间通信.docx》由会员分享,可在线阅读,更多相关《对话 UNIX 通过共享内存进行进程间通信.docx(9页珍藏版)》请在冰豆网上搜索。

对话 UNIX 通过共享内存进行进程间通信.docx

对话UNIX通过共享内存进行进程间通信

对话UNIX:

通过共享内存进行进程间通信

MartinStreicher,软件开发人员,Pixel,Byte,andComma

MartinStreicher是一位RubyonRails的自由开发人员和LinuxMagazine的前任主编。

Martin毕业于PurdueUniversity并获得计算机科学学位,从1986年起他一直从事UNIX类系统的编程工作。

他喜欢收集艺术品和玩具。

简介:

 UNIX®提供多种进程间通信技术,支持在两个或更多应用程序之间实现协作计算。

共享内存是这些技术中最快、最灵活的,而且非常容易实现。

从表面上看,UNIX®应用程序单独控制底层主机。

它随时可以访问处理器,它的内存是神圣不可侵犯的,连接它的设备只为它服务。

但是表面现象会骗人,这样有如君主一般的绝对地位只是幻想而已。

UNIX系统同时运行大量应用程序,有限的物理资源要在它们之间共享。

处理器能力被划分为时间片,应用程序映像经常被换入和换出真实内存,设备访问由需求驱动,还受到访问权限的限制。

尽管您的shell提示符不断闪烁,但是UNIX系统并非只是等着您发出命令,在幕后有许多活动正在进行。

常用缩略词

∙API:

应用程序编程接口

∙IPv4:

Internet协议第4版

∙IPv6:

Internet协议第6版

∙POSIX:

UNIX的可移植操作系统接口

尽管涉及一些复杂的机制,但是大多数应用程序不会注意到资源实际上是共享的,它们似乎是独享资源。

但是,可以编写相互交互的应用程序。

例如,一个应用程序收集或生成数据,而另一个应用程序同时监视进度并分析信息。

另一个例子是即时交换消息的聊天系统,其中有两个对等的应用程序相互收发数据。

SecureShell(ssh)也是这样,它可以在两个完全不同的主机之间进行协作。

在这些情况下,代码都要连接另一段独立的代码以交换信息,这常常需要使用某种协议协商和控制交换过程。

UNIX为实现这样的进程间通信提供了多种技术。

一些技术提供同一主机上的进程间通信,其他技术可以实现主机到主机的信息交换。

另外,各种技术的速度不同,所以必须选择最合适自己需求的技术。

还必须进行协调(实施时间控制和排他控制)。

例如,如果一个应用程序产生数据,另一个应用程序消费数据,那么当读完共享池时消费者必须停下来等待生产者。

另一方面,如果消费者无法足够快地读取池,生产者必须慢下来或暂停。

表1总结在典型的UNIX系统上可用的进程间通信形式。

表1.UNIX中的进程间通信

名称

说明

范围

用途

文件

在典型的UNIX文件中读写数据。

任意数量的进程都可以互操作。

本地

共享大数据集

管道

使用专用的文件描述符在两个进程之间传输数据。

通信只在父进程和子进程之间进行。

本地

简单的数据共享,比如生产者和消费者

命名管道

通过专用的文件描述符在进程之间交换数据。

通信可以在同一主机上的任意两个对等进程之间进行。

本地

生产者和消费者或命令-控制,比如MySQL和它的命令行查询工具

信号

通过中断通知应用程序某一情况。

本地

无法在信号中传输数据,所以信号主要用于进程管理

共享内存

通过在同一内存段中读写数据共享信息。

本地

任何类型的协作,尤其适合需要安全性的情况

套接字

完成特殊的设置过程之后,使用一般的输入/输出操作传输数据。

本地或远程

FTP、ssh和ApacheWebServer等网络服务

正如前面提到的,每种技术满足不同的需求。

假设多个进程之间的协作的复杂性大体相当,每种方法的优点和缺点如下:

∙通过一般的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:

POSIXAPI和比较老(但是仍然有效)的SystemVAPI。

因为POSIX是UNIX和Linux®及其衍生系统上的公认标准,所以我们使用此版本。

另外,POSIXAPI使用简单的文件描述符执行读写,大家应该更熟悉。

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给出一个简单的共享内存示例。

(代码取自JohnFusco撰写的TheLinuxProgrammer'sToolbox一书[由PrenticeHallProfessional于2007年3月出版,ISBN0132198576],已经得到出版商的使用授权。

)代码实现通过共享内存段通信的父进程和子进程。

清单1.共享内存示例

#include

#include

#include

#include

#include

#include

#include

voiderror_and_die(constchar*msg){

perror(msg);

exit(EXIT_FAILURE);

}

intmain(intargc,char*argv[]){

intr;

constchar*memname="sample";

constsize_tregion_size=sysconf(_SC_PAGE_SIZE);

intfd=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_tpid=fork();

if(pid==0){

u_long*d=(u_long*)ptr;

*d=0xdbeebee;

exit(0);

}

else{

intstatus;

waitpid(pid,&status,0);

printf("childwrote%#lx\n",*(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");

return0;

}

下面是代码中的一些要点:

∙对shm_open()的调用看起来应该很熟悉;它与open()函数很相似,包括初始化内存段和设置权限的方式。

在这里,内存段是全局可读、全局可写的。

如果调用成功,返回下一个未使用的文件描述符;否则,返回-1并相应地设置errno。

∙ftruncate()把文件的大小设置为region_size字节,这以前设置为系统的标准页面大小。

sysconf()是libc的组成部分。

(还可以使用shell工具getconf检查系统的配置设置。

∙mmap()连接共享内存段,返回用于对内存段直接读写字节的指针。

PROT_READ和PROT_WRITE分别表示可以读和写这个内存段中的页面。

MAP_SHARED表示对这个内存段的任何修改应该向所有参与共享的进程“公开”。

∙如果您使用过fork(),那么应该熟悉代码的计算部分。

执行fork之后,父进程和子进程获得打开的所有文件描述符和数据值的拷贝,所以指针对于它们都是有效的。

但是,pid不同。

子进程获得0,父进程获得子进程的进程ID,这个变量的值决定执行哪个if/then/else分支。

子进程向指针写一些字节,然后退出。

父进程等待子进程退出,然后读取它写的数据。

∙但是,在父进程退出之前,它必须释放共享内存。

用munmap()和shm_unlink()完成这个步骤。

这个示例非常简单。

真实的应用程序会使用信号量或其他技术控制对共享内存段的读写。

这种控制通常因应用程序而异,如果您的UNIX版本不是开放源码的,可以在BerkeleySoftwareDistribution(BSD)和Linux源代码中找到许多示例。

结束语

因为UNIX同时运行许多应用程序,所以它是非常适合监视、数据收集、协作和分布式计算以及客户机-服务器应用程序的平台。

共享内存是速度最快的进程间通信技术,而且非常灵活。

还可以把文件映射到内存,这是加快数据访问的理想解决方案。

参考资料

学习

∙Linux程序员的工具包:

研究这个工具包。

∙共享内存:

阅读关于共享内存的基础教程,进一步了解各种实现。

∙进程间通信:

进一步了解共享内存和其他进程间通信形式是如何实现的。

∙对话UNIX:

阅读本系列中的其他部分。

∙AIXandUNIX专区:

developerWorks的“AIXandUNIX专区”提供了大量与AIX系统管理的所有方面相关的信息,您可以利用它们来扩展自己的UNIX技能。

∙AIXandUNIX新手入门:

访问“AIXandUNIX新手入门”页面可了解更多关于AIX和UNIX的内容。

∙AIXandUNIX专题汇总:

AIXandUNIX专区已经为您推出了很多的技术专题,为您总结了很多热门的知识点。

我们在后面还会继续推出很多相关的热门专题给您,为了方便您的访问,我们在这里为您把本专区的所有专题进行汇总,让您更方便的找到您需要的内容。

∙AIXandUNIX下载中心:

在这里你可以下载到可以运行在AIX或者是UNIX系统上的IBM服务器软件以及工具,让您可以提前免费试用他们的强大功能。

∙IBMSystemsMagazineforAIX中文版:

本杂志的内容更加关注于趋势和企业级架构应用方面的内容,同时对于新兴的技术、产品、应用方式等也有很深入的探讨。

IBMSystemsMagazine的内容都是由十分资深的业内人士撰写的,包括IBM的合作伙伴、IBM的主机工程师以及高级管理人员。

所以,从这些内容中,您可以了解到更高层次的应用理念,让您在选择和应用IBM系统时有一个更好的认识。

∙技术书店:

阅读关于这些和其他技术主题的图书。

讨论

∙developerWorks博客:

阅读我们的博客并加入developerWorks社区。

∙加入MydeveloperWorks社区。

∙参与AIX和UNIX论坛:

oAIX论坛

oAIXfordevelopers论坛

o集群系统管理

oIBMSupportAssistant论坛

o性能工具论坛

o虚拟化论坛

o更多AIX和UNIX论坛

关于作者

MartinStreicher是一位RubyonRails的自由开发人员和LinuxMagazine的前任主编。

Martin毕业于PurdueUniversity并获得计算机科学学位,从1986年起他一直从事UNIX类系统的编程工作。

他喜欢收集艺术品和玩具。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 演讲主持

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1