Linux进程间通信----共享内存

来源:互联网 发布:淘宝国乐一号 编辑:程序博客网 时间:2024/06/01 09:49

一、共享内存

      1、共享内存的概念:

       顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问。

      2、共享内存的实现原理:

            共享内存的实现(使用映射机制):两个不同进程共享同一块物理内存,达到访问同一份资源的目的 :


         共享内存是所有进程间通信速度最快的一种方式,省去了数据的copy在消息队列中就是server和client都读取了对方的数据并拷贝下来,因此有两次拷贝。但是共享内存优缺点:他自身不提供同步于互斥机制(可以通过信号量来实现),一般申请内存,都是按照一页的大小,避免内存碎片(4K为一页)如果申请到的内存不够一页那么操作系统自动会进行向上调整,把它申请成为一页,一页半就是两页。
        共享内存的特点:生命周期随内核 。

二、共享内存的获得

       共享内存由shmget、shmat、shmdt、shmctl四个函数组成。

      1、shmget函数:

            该函数用来创建共享内存,它的原型为:

  int shmget(key_t key, size_t size, int shmflg);  
          key_t key,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1。

         size_t size ,size以字节为单位指定需要共享的内存容量。
         int shmflg,shmflg是权限标志,它的作用与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。

       2、shmat函数:

             第一次创建完共享内存时,它还不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。它的原型如下:

    void *shmat(int shm_id, const void *shm_addr, int shmflg);  
             shm_id :代表共享内存的标识
             shm_addr: 指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
             shmflg:可直接设置为0

       3、shmdt函数:

             该函数用于将共享内存从当前进程中分离。注意,将共享内存分离并不是删除它,只是使该共享内存对当前进程不再可用。它的原型如下:

int shmdt(const void *shmaddr); 
             参数shmaddr是shmat函数返回的地址指针,调用成功时返回0,失败时返回-1。

       4、shmctl函数:

             与信号量的semctl函数一样,用来控制共享内存,它的原型如下:

int shmctl(int shm_id, int command, struct shmid_ds *buf); 
             shm_id是shmget函数返回的共享内存标识符。
             command是要采取的操作,它可以取下面的三个值 :
                    IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
                    IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
                    IPC_RMID:删除共享内存段
             buf是一个结构指针,它指向共享内存模式和访问权限的结构。
             shmid_ds结构至少包括以下成员:  
    struct shmid_ds      {          uid_t shm_perm.uid;          uid_t shm_perm.gid;          mode_t shm_perm.mode;      };  

三、实现基于共享内存的通信

       代码块:

      1、shm.h

#ifndef _SHM_H_#define _SHM_H_#define PATHNAME "."#define PROJ_ID 0x6666#include<stdio.h>#include <sys/ipc.h>#include <sys/shm.h>#include <unistd.h>#include <sys/types.h>#include <sys/wait.h>int GetShm();int CreateShm();char* Shmat(int shmid);int  Shmdt(char*add);int ComShm();#endif
 
    2、shm.c

#include"shm.h"int ComShm(int flag){  key_t key=ftok(PATHNAME,PROJ_ID);  if(key<0)  {       perror("ftok");       return -1;  }  int shmid=shmget(key,4096,flag|0666);  if(shmid<0)  {       perror("shmget");       return -2;  }  return shmid;}int CreateShm(){   return ComShm(IPC_CREAT|IPC_EXCL);}int GetShm(){     return ComShm(IPC_CREAT);}int DestroyShm(int shmid){           if(shmctl(shmid,IPC_RMID,NULL)<0)          {               perror("shmctl");               return -1;          }          return 0;}char* Shmat(int shmid){  return (char*)shmat(shmid,NULL,0);}int Shmdt(char*add){   if(shmdt(add)<0)   {        perror("shmdt");        return-1;   }   return 0;}

       3、test.c
#include"shm.h"int main(){     int shmid=CreateShm();     pid_t id=fork();     if(id==0)     {//child        char*buf=Shmat(shmid);          int i=0;          while(i<4096)          {               buf[i]='A'+i;               i++;          }          buf[i]=0;          Shmdt(buf);     }     else     {//father         char*buf=Shmat(shmid);          usleep(123456);          printf("%s\n",buf);          Shmdt(buf);          wait(NULL);          DestroyShm(shmid);     }     return 0;}
     4、程序运行结果:

     5、ipc 命令:
       ipcs -m 查看共享内存
       ipcrm -m shmid 删除共享内存
     6、使用共享内存的优缺点
       1)优点:我们可以看到使用共享内存进行进程间的通信真的是非常方便,而且函数的接口也简单,数据的共享还使进程间的数据不用传送,而是直接访问内存,也加快了程序的效率。同时,它也不像匿名管道那样要求通信的进程有一定的父子关系。共享内存相比其他几种方式有着更方便的数据控制能力,数据在读写过程中会更透明。当成功导入一块共享内存后,它只是相当于一个字符串指针来指向一块内存,在当前进程下用户可以随意的访问。
      2)缺点:共享内存没有提供同步的机制数据写入进程或数据读出进程中,需要附加的数据结构控制。这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。