linux 共享内存 同步地址是唯一的吗

linux 共享内存 - farsight2009的日志 -
电子工程世界-论坛
请完成以下验证码
linux 共享内存
已有 4587 次阅读 13:11
可以说,共享内存是一种最为高效的进程间通信方式,因为进程可以直接读写内存,不需要任何数据的复制。为了在多个进程间交换信息,内核专门留出了一块内存区,这段内存区可以由需要访问的进程将其映射到自己的私有地址空间。因此,进程就可以直接读写这一内存区而不需要进行数据的复制,从而大大提高了效率。当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。其原理示意图如图1所示。
图1&&共享内存原理示意图& & 共享内存的实现分为两个步骤:第一步是创建共享内存,这里用到的函数是shmget(),也就是从内存中获得一段共享内存区域;第二步是映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中,这里使用的函数是shmat()。到这里,就可以使用这段共享内存了,也就是可以使用不带缓冲的I/O读写命令对其进行操作。除此之外,还有撤销映射的操作,其函数为shmdt()。这里主要介绍这3个函数。
& & 表1 列举了shmget()函数的语法要点。
表1&&shmget()函数语法要点所需头文件#include
& & #include
& & #include 函数原型int shmget(key_t key, int size, int shmflg)函数传入值key:共享内存的键值,多个进程可以通过它访问同一个共享内存,其中有个特殊值IPC_PRIVATE,用于创建当前进程的私有共享内存size:共享内存区大小shmflg:同open()函数的权限位,也可以用八进制表示法函数返回值成功:共享内存段标识符出错:-1& & 表2列举了shmat()函数的语法要点。
表2&&shmat()函数语法要点所需头文件#include
& & #include
& & #include 函数原型char *shmat(int shmid, const void *shmaddr, int shmflg)函数传入值shmid:要映射的共享内存区标识符shmaddr:将共享内存映射到指定地址(若为0则表示系统自动分配地址并把该段共享内存映射到调用进程的地址空间)shmflgSHM_RDONLY:共享内存只读默认0:共享内存可读写函数返回值成功:被映射的段地址出错:-1& & 表3列举了shmdt()函数的语法要点。
表3&&shmdt()函数语法要点所需头文件#include
& & #include
& & #include 函数原型int shmdt(const void *shmaddr)函数传入值shmaddr:被映射的共享内存段地址函数返回值成功:0出错:-1& & 以下实例说明了如何使用基本的共享内存函数。首先创建一个共享内存区(采用的共享内存的键值为IPC_PRIVATE,是因为本实例中创建的共享内存是父子进程间的共用部分),然后创建子进程,在父子两个进程中将共享内存分别映射到各自的进程地址空间中。
& & 父进程先等待用户输入,然后将用户输入的字符串写入到共享内存,之后向共享内存的头部写入“WROTE”字符串表示父进程已成功写入数据。子进程一直等到共享内存的头部字符串为“WROTE”,然后将共享内存的有效数据(在父进程中用户输入的字符串)在屏幕上打印。父子两个进程在完成以上工作后,分别解除与共享内存的映射关系。
& & 最后在子进程中删除共享内存。因为共享内存自身并不提供同步机制,所以应额外实现不同进程间的同步(如信号量)。为了简单起见,在本实例中用标志字符串来实现非常简单的父子进程间的同步。
& & 这里要介绍的一个命令是ipcs,用于报告进程间通信机制状态,它可以查看共享内存、消息队列等各种进程间通信机制的情况,这里使用了system()函数调用shell命令“ipcs”。程序源代码如下:
& & /* shmem.c */
& && &&&#include
& && &&&#include
& && &&&#include
& && &&&#include
& && &&&#include
& && &&&#include
& && && && &#define BUFFER_SIZE 2048
& && && && &int main()
& && && && &pid_
& && && && &
& && && && &char *shm_
& && && && &char flag[] = \"WROTE\";
& && && && &char *
& && && && && & /* 创建共享内存 */
& && && && &if ((shmid = shmget(IPC_PRIVATE, BUFFER_SIZE, 0666)) < 0)
& && && && &{
& && && && && & perror(\"shmget\");
& && && && && & exit(1);
& && && && &}
& && && && &else
& && && && &{
& && && && &printf(\"Create shared-memory: %d\\n\",shmid);
& && && && &}
& && && && && & /* 显示共享内存情况 */
& && && && &system(\"ipcs -m\");
& && && && && & pid = fork();
& && && && &if (pid == -1)
& && && && &{
& && && && && & perror(\"fork\");
& && && && && & exit(1);
& && && && &}
& && && && &else if (pid == 0) /* 子进程处理 */
& && && && &{
& && && && && & /* 映射共享内存 */
& && && && && & if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
& && && && && & {
& && && && && && &&&perror(\"Child: shmat\");
& && && && && && &&&exit(1);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&printf(\"Child: Attach shared-memory: %p\\n\", shm_addr);
& && && && && & }
& && && && && & system(\"ipcs -m\");
& && && && && && &&&/* 通过检查在共享内存的头部是否有标志字符串“WROTE”来确认父进程已经向共享内存写入有效数据 */
& && && && && & while (strncmp(shm_addr, flag, strlen(flag)))
& && && && && & {
& && && && && && &&&printf(\"Child: Wait for enable data...\\n\");
& && && && && && &&&sleep(5);
& && && && && & }
& && && && && && &&&/* 获取共享内存的有效数据并显示 */
& && && && && & strcpy(buff, shm_addr + strlen(flag));
& && && && && & printf(\"Child: Shared-memory :%s\\n\", buff);
& && && && && && &&&/* 解除共享内存映射 */
& && && && && & if ((shmdt(shm_addr)) < 0)
& && && && && & {
& && && && && && &&&perror(\"shmdt\");
& && && && && && &&&exit(1);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&printf(\"Child: Deattach shared-memory\\n\");
& && && && && & }
& && && && && & system(\"ipcs -m\");
& && && && && && &&&/* 删除共享内存 */
& && && && && & if (shmctl(shmid, IPC_RMID, NULL) == -1)
& && && && && & {
& && && && && && &&&perror(\"Child: shmctl(IPC_RMID)\\n\");
& && && && && && &&&exit(1);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&printf(\"Delete shared-memory\\n\");
& && && && && & }
& && && && && && &&&system(\"ipcs -m\");
& && && && &}
& && && && &else /* 父进程处理 */
& && && && &{
& && && && && & /* 映射共享内存 */
& && && && && & if ((shm_addr = shmat(shmid, 0, 0)) == (void*)-1)
& && && && && & {
& && && && && && &&&perror(\"Parent: shmat\");
& && && && && && &&&exit(1);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&printf(\"Parent: Attach shared-memory: %p\\n\", shm_addr);
& && && && && & }
& && && && && && &&&sleep(1);
& && && && && & printf(\"\\nInput some string:\\n\");
& && && && && & fgets(buff, BUFFER_SIZE, stdin);
& && && && && & strncpy(shm_addr + strlen(flag), buff, strlen(buff));
& && && && && & strncpy(shm_addr, flag, strlen(flag));
& && && && && && &&&/* 解除共享内存映射 */
& && && && && & if ((shmdt(shm_addr)) < 0)
& && && && && & {
& && && && && && &&&perror(\"Parent: shmdt\");
& && && && && && &&&exit(1);
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && &&&printf(\"Parent: Deattach shared-memory\\n\");
& && && && && & }
& && && && && & system(\"ipcs -m\");
& && && && && && &&&waitpid(pid, NULL, 0);& & & & & & & &
& && && && && & printf(\"Finished\\n\");
& && && && &}
& && && && && & exit(0);
& && &&&}& &&&& & 下面是运行结果,从该结果中可以看出,nattch的值随着共享内存状态的变化而变化,共享内存的值根据不同的系统会有所不同。
& & $ ./shmem
& && &&&Create shared-memory: 753665
& && &&&/* 在刚创建共享内存时(尚未有任何地址映射)共享内存的情况 */
& && &&&------ Shared Memory Segments --------
& & key& && &&&shmid& & owner& & perms& & bytes& & nattch& & status& && &
& && &&&0x665& &david& & 666& && &2048& && &0& && && && && && && &&&
& && && && &Child: Attach shared-memory: 0xb7f59000 /* 共享内存的映射地址 */
& && &&&Parent: Attach shared-memory: 0xb7f59000
& && &&&/* 在父子进程中进行共享内存的地址映射后共享内存的情况 */
& && &&&------ Shared Memory Segments --------
& & key& && &&&shmid& & owner& & perms& & bytes& & nattch& & status& && &
& && &&&0x665& &david& & 666& && &2048& && &2& && && && && && && &&&
& && && && &Child: Wait for enable data...
& && && && &Input some string:
& && &&&Hello /* 用户输入字符串“Hello” */
& && &&&Parent: Deattach shared-memory
& && &&&/* 在父进程中解除共享内存的映射关系后共享内存的情况 */
& && &&&------ Shared Memory Segments --------
& & key& && &&&shmid& & owner& & perms& & bytes& & nattch& & status& && &
& && &&&0x665& &david& & 666& && &2048& && &1& && && && && && && &&&
& && &&&/* 在子进程中读取共享内存的有效数据并打印 */
& && &&&Child: Shared-memory :hello
& && && && &Child: Deattach shared-memory
& && &&&/* 在子进程中解除共享内存的映射关系后共享内存的情况 */
& && &&&------ Shared Memory Segments --------
& & key& && &&&shmid& & owner& & perms& & bytes& & nattch& & status& && &
& && &&&0x665& &david& & 666& && &2048& && &0& && && && && && && &&&
& && && && &Delete shared-memory
& && &&&/* 在删除共享内存后共享内存的情况 */
& && &&&------ Shared Memory Segments --------
& & key& && &&&shmid& & owner& & perms& & bytes& & nattch& & status& && &
& && && && &Finished& &&&& & 本文选自华清远见教材
作者的其他最新日志
评论 ( 个评论)
EEWORLD 官方微信
Powered byLinux下共享内存在进程空间的什么位置? - 知乎5被浏览567分享邀请回答1添加评论分享收藏感谢收起0添加评论分享收藏感谢收起写回答zhuanlan_ 删除。|8 篇文章23 人订阅相关文章来自专栏915来自专栏13来自专栏13来自专栏8来自专栏19linux共享内存和mmap的区别_百度知道
linux共享内存和mmap的区别
我有更好的答案
共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现更安全通信,往往还与信号灯等同步机制共同使用。mmap的机制如:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。 shm的机制:每个进程的共享内存都直接映射到实际物理存储器里面。1、mmap保存到实际硬盘,实际存储并没有反映到主存上。优点:储存量可以很大(多于主存);缺点:进程间读取和写入速度要比主存的要慢。2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。优点,进程间访问速度(读写)比磁盘要快;缺点,储存量不能非常大(多于主存)使用上看:如果分配的存储量不大,那么使用shm;如果存储量大,那么使用mmap。
采纳率:80%
  共享内存的创建  根据理论:  1. 共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现更安全通信,往往还与信号灯等同步机制共同使用。  mmap的机制如:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。  shm的机制:每个进程的共享内存都直接映射到实际物理存储器里面。  结论:  1、mmap保存到实际硬盘,实际存储并没有反映到主存上。优点:储存量可以很大(多于主存)(这里一个问题,需要高手解答,会不会太多拷贝到主存里面???);缺点:进程间读取和写入速度要比主存的要慢。  2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。优点,进程间访问速度(读写)比磁盘要快;缺点,储存量不能非常大(多于主存)  使用上看:如果分配的存储量不大,那么使用shm;如果存储量大,那么使用shm。  参看百度:  mmap就是一个文件操作  看这些百度的描述:  mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。 成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1。errno被设为以下的某个值 EACCES:访问出错EAGAIN:文件已被锁定,或者太多的内存已被锁定EBADF:fd不是有效的文件描述词EINVAL:一个或者多个参数无效 ENFILE:已达到系统对打开文件的限制ENODEV:指定文件所在的文件系统不支持内存映射ENOMEM:内存不足,或者进程已超出最大内存映射数量 EPERM:权能不足,操作不允许ETXTBSY:已写的方式打开文件,同时指定MAP_DENYWRITE标志SIGSEGV:试着向只读区写入 SIGBUS:试着访问不属于进程的内存区参数fd为即将映射到进程空间的文件描述字,  一般由open()返回,同时,fd可以指定为-1,此时须指定 flags参数中的MAP_ANON,表明进行的是匿名映射(不涉及具体的文件名,避免了文件的创建及打开,很显然只能用于具有亲缘关系的进程间通信)  相关文章参考:  mmap函数是unix/linux下的系统调用,来看《Unix Netword programming》卷二12.2节有详细介绍。  mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然mmap()实现共享内存也是其主要应用之一。  mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再 调用read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了.  简单说就是把一个文件的内容在内存里面做一个映像,内存比磁盘快些。  基本上它是把一个档案对应到你的virtual memory 中的一段,并传回一个指针。  重写总结:  1、mmap实际就是操作“文件”。  2、映射文件,除了主存的考虑外。shm的内存共享,效率应该比mmap效率要高(mmap通过io和文件操作,或“需要写完后用msync()同步一下”);当然mmap映射操作文件,比直接操作文件要快些;由于多了一步msync应该可以说比shm要慢了吧???  3、另一方面,mmap的优点是,操作比shm简单(没有调用比shm函数复杂),我想这也是许多人喜欢用的原因,包括nginx。  缺点,还得通过实际程序测试,确定!!!    修正理解(这也真是的,这个网站没办法附加;只能重写了):  今天又细心研究了一下,发现百度这么一段说明:  2、系统调用mmap()用于共享内存的两种方式:  (1)使用普通文件提供的内存映射:适用于任何进程之间;此时,需要打开或创建一个文件,然后再调用mmap();典型调用代码如下:  fd=open(name, flag, mode);  if(fd&0)  ...  ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0); 通过mmap()实现共享内存的通信方式有许多特点和要注意的地方,我们将在范例中进行具体说明。  (2)使用特殊文件提供匿名内存映射:适用于具有亲缘关系的进程之间;由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后调用fork()。那么在调用fork()之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,父子进程就可以通过映射区域进行通信了。注意,这里不是一般的继承关系。一般来说,子进程单独维护从父进程继承下来的一些变量。而mmap()返回的地址,却由父子进程共同维护。  看了一下windows“内存映射文件”:  内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,只是内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而非系统的页文件,而且在对该文件进行操作之前必须首先对文件进行映射,就如同将整个文件从磁盘加载到内存。由此可以看出,使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。另外,实际工程中的系统往往需要在多个进程之间共享数据,如果数据量小,处理方法是灵活多变的,如果共享数据容量巨大,那么就需要借助于内存映射文件来进行。实际上,内存映射文件正是解决本地多个进程间数据共享的最有效方法。    这里再总结一次:  1、mmap有两种方式,一种是映射内存,它把普通文件映射为实际物理内存页,访问它就和访问物理内存一样(这也就和shm的功能一样了)(同时不用刷新到文件)  2、mmap可以映射文件,不确定会不会像windows“内存映射文件”一样的功能,如果是,那么他就能映射好几G甚至好几百G的内存数据,对大数据处理将提供强大功能了???  3、shm只做内存映射,和mmap第一个功能一样!只不过不是普通文件而已,但都是物理内存。
本回答被提问者和网友采纳
mmap的机制如:就是在磁盘上建立一个文件,每个进程存储器里面,单独开辟一个空间来进行映射。如果多进程的话,那么不会对实际的物理存储器(主存)消耗太大。shm的机制:每个进程的共享内存都直接映射到实际物理存储器里面。 1、mmap保存到实际硬盘,实际存储并没有反映到主存上2、shm保存到物理存储器(主存),实际的储存量直接反映到主存上。 使用上看:如果分配的存储量不大,那么使用shm;如果存储量大,那么使用shm。 以上内容来源,
为您推荐:
其他类似问题
共享内存的相关知识
&#xe675;换一换
回答问题,赢新手礼包&#xe6b9;
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。博客访问: 306908
博文数量: 60
博客积分: 86
博客等级: 民兵
技术积分: 2146
注册时间:
为今天而努力的人很平凡,为昨天而努力的人叫失败,只有为美好明天而战斗不止才叫精彩!
分类: LINUX 20:53:30
/*共享内存允许两个或多个进程进程共享同一块内存(这块内存会映射到各个进程自己独立的地址空间)
& 从而使得这些进程可以相互通信。
& 在GNU/Linux中所有的进程都有唯一的虚拟地址空间,而共享内存应用编程接口API允许一个进程使
& 用公共内存区段。但是对内存的共享访问其复杂度也相应增加。共享内存的优点是简易性。
& 使用消息队列时,一个进程要向队列中写入消息,这要引起从用户地址空间向内核地址空间的一次复制,
& 同样一个进程进行消息读取时也要进行一次复制。共享内存的优点是完全省去了这些操作。
& 共享内存会映射到进程的虚拟地址空间,进程对其可以直接访问,避免了数据的复制过程。
& 因此,共享内存是GNU/Linux现在可用的最快速的IPC机制。
& 进程退出时会自动和已经挂接的共享内存区段分离,但是仍建议当进程不再使用共享区段时
& 调用shmdt来卸载区段。
& 注意,当一个进程分支出父进程和子进程时,父进程先前创建的所有共享内存区段都会被子进程继承。
如果区段已经做了删除标记(在前面以IPC——RMID指令调用shmctl),而当前挂接数已经变为0,
& 这个区段就会被移除。
& shmget(& )& 创建一个新的共享内存区段
&&&&&&&&&&&&& 取得一个共享内存区段的描述符
& shmctl(& )& 取得一个共享内存区段的信息
&&&&&&&&&&&&& 为一个共享内存区段设置特定的信息
&&&&&&&&&&&&& 移除一个共享内存区段
& shmat(& )&& 挂接一个共享内存区段
& shmdt(& )&& 于一个共享内存区段的分离
//创建一个共享内存区段,并显示其相关信息,然后删除该内存共享区
#include & //getpagesize(& )
#define MY_SHM_ID 67483
int main(& )
&&&&&&& //获得系统中页面的大小
&&&&&&& printf( "page size=%d/n",getpagesize(& ) );
&&&&&&& //创建一个共享内存区段
&&&&&&& int shmid,
&&&&&&& shmid=shmget( MY_SHM_ID,|IPC_CREAT );
&&&&&&& //创建了一个4KB大小共享内存区段。指定的大小必须是当前系统架构
&&&&&&& //中页面大小的整数倍
&&&&&&& if( shmid>0 )
&&&&&&&&&&& printf( "Create a shared memory segment %d/n",shmid );
&&&&&&& //获得一个内存区段的信息
&&&&&&& struct shmid_
&&&&&&& //shmid=shmget( MY_SHM_ID,0,0 );//示例怎样获得一个共享内存的标识符
&&&&&&& ret=shmctl( shmid,IPC_STAT,&shmds );
&&&&&&& if( ret==0 )
&&&&&&&&&&& {
&&&&&&&&&&&&&&& printf( "Size of memory segment is %d/n",shmds.shm_segsz );
printf( "Numbre of attaches %d/n",( int )shmds.shm_nattch );
&&&&&&&&&&& }
&&&&&&& else
&&&&&&&&&&& {
&&&&&&&&&&&&&&& printf( "shmctl(& ) call failed/n" );
&&&&&&&&&&& }
&&&&&&& //删除该共享内存区
&&&&&&& ret=shmctl( shmid,IPC_RMID,0 );
&&&&&&& if( ret==0 )
&&&&&&&&&&& printf( "Shared memory removed /n" );
&&&&&&& else
&&&&&&&&&&& printf( "Shared memory remove failed /n" );
&&&&&&& return 0;
//共享内存区段的挂载,脱离和使用
//理解共享内存区段就是一块大内存
#define MY_SHM_ID 67483
int main(& )
&&&&&&& //共享内存区段的挂载和脱离
&&&&&&& int shmid,
&&&&&&& void*
&&&&&&& shmid=shmget( MY_SHM_ID,0,0 );
&&&&&&& if( shmid>=0 )
&&&&&&&&&&& {
&&&&&&&&&&&&&&& mem=shmat( shmid,( const void* )0,0 );
&&&&&&&&&&&&&&& //shmat()返回进程地址空间中指向区段的指针
&&&&&&&&&&&&&&& if( ( int )mem!=-1 )
&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&& printf( "Shared memory was attached in our address space at %p/n",mem );
&&&&&&&&&&&&&&&&&&&&&&& //向共享区段内存写入数据
&&&&&&&&&&&&&&&&&&&&&&& strcpy( ( char* )mem,"This is a test string./n" );
&&&&&&&&&&&&&&&&&&&&&&& printf( "%s/n",(char*)mem );
&&&&&&&&&&&&&&&&&&&&&&& //脱离共享内存区段
&&&&&&&&&&&&&&&&&&&&&&& ret=shmdt( mem );
&&&&&&&&&&&&&&&&&&&&&&& if( ret==0 )
&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Successfully detached memory /n" );
&&&&&&&&&&&&&&&&&&&&&&& else
&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Memory detached failed %d/n",errno );
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& else
&&&&&&&&&&&&&&&&&&& printf( "shmat(& ) failed/n" );
&&&&&&&&&&&&&&
&&&&&&&&&&& }
&&&&&&& else
&&&&&&&&&&& printf( "shared memory segment not found/n" );
&&&&&&& return 0;
/*内存共享区段与旗语和消息队列不同,一个区段可以被锁定。
& 被锁定的区段不允许被交换出内存。这样做的优势在于,与其
& 把内存区段交换到文件系统,在某个应用程序调用时再交换回内存,
& 不如让它一直处于内存中,且对多个应用程序可见。从提升性能的角度
& 来看,很重要的。
shmid=shmget( MY_SHM_ID,0,0 );
ret=shmctl( shmid,SHM_LOCK,0 );
if( ret==0 )
&&& printf( "Locked!/n" );
////////////////////////////////////////////////////////////////////////
/*使用旗语协调共享内存的例子
& 使用和编译命令
& gcc -Wall test.c -o test
& ./test create
& ./test use a &
& ./test use b &
& ./test read &
& ./test remove
#define MY_SHM_ID 34325
#define MY_SEM_ID 23234
#define MAX_STRING 200
typedef struct
&&& int semID;
&&& char string[ MAX_STRING+1 ];
}MY_BLOCK_T;
int main(int argc,char** argv)
&&&&&&& int shmid,ret,i;
&&&&&&& MY_BLOCK_T*
&&&&&&& //make sure there is a command
&&&&&&& if( argc>=2 )
&&&&&&&&&&& {
&&&&&&&&&&&&&&& //create the shared memory segment and init it
&&&&&&&&&&&&&&& //with the semaphore
&&&&&&&&&&&&& if( !strncmp(argv[ 1 ],"create",6) )
&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&& //create the shared memory segment and semaphore
&&&&&&&&&&&&&&&&&&&&&&& printf( "Creating the shared memory/n" );
&&&&&&&&&&&&&&&&&&&&&&& shmid=shmget( MY_SHM_ID,sizeof( MY_BLOCK_T ),( IPC_CREAT|0666 ) );
&&&&&&&&&&&&&&&&&&&&&&& block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
&&&&&&&&&&&&&&&&&&&&&&& block->counter=0;
&&&&&&&&&&&&&&&&&&&&&&& //create the semaphore and init
&&&&&&&&&&&&&&&&&&&&&&& block->semID=semget(MY_SEM_ID,1,( IPC_CREAT|0666 ));
&&&&&&&&&&&&&&&&&&&&&&& sb.sem_num=0;
&&&&&&&&&&&&&&&&&&&&&&& sb.sem_op=1;
&&&&&&&&&&&&&&&&&&&&&&& sb.sem_flg=0;
&&&&&&&&&&&&&&&&&&&&&&& semop( block->semID,&sb,1 );
&&&&&&&&&&&&&&&&&&&&&&& //now detach the segment
&&&&&&&&&&&&&&&&&&&&&&& shmdt( ( void* )block );
&&&&&&&&&&&&&&&&&&&&&&& printf( "Create the shared memory and semaphore successuflly/n" );
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& else if( !strncmp(argv[ 1 ],"use",3) )
&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&& /*use the segment*/
&&&&&&&&&&&&&&&&&&&&&&& //must specify& also a letter to write to the buffer
&&&&&&&&&&&&&&&&&&&&&&& if( argc<3 ) exit( -1 );
&&&&&&&&&&&&&&&&&&&&&&& user=( char )argv[ 2 ][ 0 ];
&&&&&&&&&&&&&&&&&&&&&&& //grab the segment
&&&&&&&&&&&&&&&&&&&&&&& shmid=shmget( MY_SHM_ID,0,0 );
&&&&&&&&&&&&&&&&&&&&&&& block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&& /*##########重点就是使用旗语对共享区的访问###########*/
&&&&&&&&&&&&&&&&&&&&&&& for( i=0;i<100;++i )
&&&&&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&& sleep( 1 ); //设置成1s就会看到 a/b交替出现,为0则a和b连续出现
&&&&&&&&&&&&&&&&&&&&&&& //grab the semaphore
&&&&&&&&&&&&&&&&&&&&&&& sb.sem_num=0;
&&&&&&&&&&&&&&&&&&&&&&& sb.sem_op=-1;
&&&&&&&&&&&&&&&&&&&&&&& sb.sem_flg=0;
&&&&&&&&&&&&&&&&&&&&&&& if( semop( block->semID,&sb,1 )!=-1 )
&&&&&&&&&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //write the letter to the segment buffer
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //this is our CRITICAL SECTION
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& block->string[ block->counter++ ]=
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sb.sem_num=0;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sb.sem_op=1;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& sb.sem_flg=0;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if( semop( block->semID,&sb,1 )==-1 )
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Failed to release the semaphore/n" );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& else
&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Failed to acquire the semaphore/n" );
&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&& //do some clear work
&&&&&&&&&&&&&&&&&&&&&&& ret=shmdt(( void*)block);
&&&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& else if( !strncmp(argv[ 1 ],"read",4) )
&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&& //here we will read the buffer in the shared segment
&&&&&&&&&&&&&&&&&&&&&&& shmid=shmget( MY_SHM_ID,0,0 );
&&&&&&&&&&&&&&&&&&&&&&& if( shmid!=-1 )
&&&&&&&&&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& block->string[ block->counter+1 ]=0;
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "%s/n",block->string );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Length=%d/n",block->counter );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ret=shmdt( ( void*)block );
&&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&&&&&& else
&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Unable to read segment/n" );
&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& else if( !strncmp(argv[ 1 ],"remove",6) )
&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&& shmid=shmget( MY_SHM_ID,0,0 );
&&&&&&&&&&&&&&&&&&&&&&& if( shmid>=0 )
&&&&&&&&&&&&&&&&&&&&&&&&&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& block=( MY_BLOCK_T* )shmat( shmid,( const void* )0,0 );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //remove the semaphore
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ret=semctl( block->semID,0,IPC_RMID );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if( ret==0 )
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Successfully remove the semaphore /n" );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& //remove the shared segment
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ret=shmctl( shmid,IPC_RMID,0 );
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& if( ret==0 )
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& printf( "Successfully remove the segment /n" );
&&&&&&&&&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&& else
&&&&&&&&&&&&&&&&&&& printf( "Unkonw command/n" );
&&&&&&&&&&& }
&&&&&&& return 0;
阅读(4552) | 评论(0) | 转发(5) |
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 linux 进程间共享内存 的文章

 

随机推荐