linux下两种共享内存通信方式(zz)

来源:互联网 发布:java中的final 编辑:程序博客网 时间:2024/05/21 18:46

转自:

http://www.linuxgraphics.cn/gui/ipc_shrmem.html


进程间通信之共享内存
作者: 刘鹏
日期: 2008-10-22
本文介绍了共享内存的两种方法,第一种是通过 mmap 实现共享内存,第二种是 System V 进程间通信机制。

共享内存简介

共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。1

采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据1:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。1

本文介绍了共享内存的两种方法,第一种是通过 mmap 实现共享内存,第二种是 System V 进程间通信机制。

mmap 方式

mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。

实际上,mmap()系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件的操作。而Posix或系统V的共享内存IPC则纯粹用于共享目的,当然 mmap() 实现共享内存也是其主要应用之一。

下图是 mmap 将文件映射到进程地址空间的示意图3

mmap 示意图mmap 示意图

创建文件并将其 mmap 到地址空间的主要流程如下所示:

    int fd;    void* memptr;    /* create a tmp file.*/    fd = open ("/var/tmp/mmapfile", O_WRONLY | O_CREAT | O_TRUNC, 0644);    /* Write data to file */    write (fd, &data, sizeof (data));    /* mmap file to address space of calling process*/    memptr = mmap (0, sizeof (data), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);    ......    /* Delete the mapping .*/    unlink ("/var/tmp/mmapfile");    munmap (memptr, sizeof (data));

映射文件到自己的地址空间的主要流程如下所示:

    int fd;    void* memptr;    fd = open ("/var/tmp/mmapfile", O_RDONLY);    size = lseek (fd, 0, SEEK_END);    memptr = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);    ......    unlink ("/var/tmp/mmapfile");    munmap (memptr, size);

System V 共享内存

System V 共享内存是通过映射特殊文件系统 shm 中的文件实现进程间的共享内存通信,即把所有共享数据放在共享内存区域 (IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。2

创建共享内存的主要流程如下面的伪代码所示:

    key_t shnm_key;    int shmid;    void* memptr;    /* get a shm key */    shm_key = ftok (filename, 0);    /* allocate a shared memory segment  */    shmid = shmget (shm_key, sizem SHM_PARAM | IPC_CREAT | IPC_EXCL);    /* Attach the shared memory segment identified by shmid to the address space    of calling process  */    memptr = shmat (shmid, 0, 0);    /* write data to shared memory */    memcpy (memptr, &data, sizeof (data));    /* Mark the segment to be destroyed. The segment will only actually be       destroyed after the last process detached it.  */    shmctl (shmid, IPC_RMID, NULL);    .......    /* Detached the shared memory segment from the address space of    calling process. */    shmdt (memptr);

attach 共享内存到 calling process 的流程如下所示:

    void* memptr;    get shmid from shared memory segment creator    /* Attach shared memory segment to the address space of calling process.*/    memptr = shmat(shmid, 0, SHM_RDONLY);    ... ...    /* Detached the shared memory segment.*/    shmdt (memptr);

See Also

在 IBM Developworks 上有两篇文章对 mmap 和 System V 这两种共享内存方式进行了详细描述和比较:

  1. Linux 环境进程间通信(五):共享内存 (上)
  2. Linux 环境进程间通信(五):共享内存 (下)
  3. mmap 的示意图来自 http://www.bitctrl.com/qnx/qnx6_sysarch/qnx6_sysarch_2b.htm
  4. mmap、munmap、shmget, shmat, shmctl, shmdt 手册
  5. sharedmem.tar.gz 是我整理的一个共享内存的示例代码。

原创粉丝点击