一. 共享内存介绍
系统V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的
进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。系统调用mmap()通
过映射一个普通文件实现共享内存。系统V则是通过映射shm文件系统中的文件实现进程间的共享内存通信。
也就是说,每个共享内存区域对应shm文件系统的一个文件.
二、系统V共享内存API
对于系统V共享内存,主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。
#include <sys/ipc.h>
#include <sys/shm.h>
shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。
shmat()把共享内存区域映射到调用进程的地址空间中去,这样,进程就可以方便地对共享区域进行访问操作。
shmdt()调用用来解除进程对共享内存区域的映射。
shmctl实现对共享内存区域的控制操作。
注:shmget的内部实现包含了许多重要的系统V共享内存机制;shmat在把共享内存区域映射到进程空间时,并不真正改变进程的页表。当进程第一次访问内存映射区域访问时,会因为没有物理页表的分配而导致一个缺页异常,然后内核再根据相应的存储管理机制为共享内存映射区域分配相应的页表。
三. 系统V共享内存范例
范例1
两个进程, 进程A创建一块共享内存, 写下Hello, World然后退出. 进程B根据key得到进程A创建的共享内存, 然后读取
共享内存中的数据. 并打印出来. 示意图如下:
进程A的代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <error.h>
#define SHM_SIZE 4096
#define SHM_MODE (SHM_R | SHM_W) /* user read/write */
int main(void)
{
int shmid;
char *shmptr;
if ( (shmid = shmget(0x44, SHM_SIZE, SHM_MODE | IPC_CREAT)) < 0)
perror("shmget");
if ( (shmptr = shmat(shmid, 0, 0)) == (void *) -1)
perror("shmat");
/* 往共享内存写数据 */
sprintf(shmptr, "%s", "hello, world");
exit(0);
}
进程B的代码:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <error.h>
#define SHM_SIZE 4096
#define SHM_MODE (SHM_R | SHM_W | IPC_CREAT) /* user read/write */
int main(void)
{
int shmid;
char *shmptr;
if ( (shmid = shmget(0x44, SHM_SIZE, SHM_MODE | IPC_CREAT)) < 0)
perror("shmget");
if ( (shmptr = shmat(shmid, 0, 0)) == (void *) -1)
perror("shmat");
/* 从共享内存读数据 */
printf("%s\n", shmptr);
exit(0);
}
总结:
1、系统V共享内存中的数据,从来不写入到实际磁盘文件中去;而通过mmap()映射普通文件实现的共享内存通信可以
指定何时将数据写入磁盘文件中。 注:系统V共享内存机制实际是通过shm文件系统中的文件
实现的,shm文件系统的安装点在交换分区上,系统重新引导后,所有的内容都丢失。
2、系统V共享内存是随内核持续的,即使所有访问共享内存的进程都已经正常终止,共享内存区仍然存在(除非显式删
除共享内存),在内核重新引导之前,对该共享内存区域的任何改写操作都将一直保留。
3、通过调用mmap()映射普通文件进行进程间通信时,一定要注意考虑进程何时终止对通信的影响。而通过系统V共享
内存实现通信的进程则不然。
四. shm文件系统内核实现 (linux-1.2.13)
每一个新创建的共享内存对象都用一个shmid_kernel数据结构来表达。系统中所有的shmid_kernel数据结构都保存在shm_segs向量表中,该向量表的每一个元素都是一个指向shmid_kernel数据结构的指针。
shm_segs向量表的定义如下:
struct shmid_kernel *shm_segs[SHMMNI];
SHMMNI为128,表示系统中最多可以有128个共享内存对象。如下图所示:
数据结构shmid_kernel的定义如下:
struct shmid_kernel
{
struct shmid_ds u; /* the following are private */
unsigned long shm_npages; /* size of segment (pages) */
unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */
struct vm_area_struct *attaches; /* descriptors for attaches */
};
其中:
shm_pages代表该共享内存对象的所占据的内存页面数组,数组里面的每个元素当然是每个内存页面的起始地址.
shm_npages则是该共享内存对象占用内存页面的个数,以页为单位。这个数量当然涵盖了申请空间的最小整数倍.
(A new shared memory segment, with size equal to the value of size rounded up to a multiple of PAGE_SIZE)
shmid_ds是一个数据结构,它描述了这个共享内存区的认证信息,字节大小,最后一次粘附时间、分离时间、改变时间,创建该共享区域的进程,最后一次对它操作的进程,当前有多少个进程在使用它等信息。
其定义如下:
struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
__kernel_time_t shm_atime; /* last attach time */
__kernel_time_t shm_dtime; /* last detach time */
__kernel_time_t shm_ctime; /* last change time */
__kernel_ipc_pid_t shm_cpid; /* pid of creator */
__kernel_ipc_pid_t shm_lpid; /* pid of last operator */
unsigned short shm_nattch; /* no. of current attaches */
unsigned short shm_unused; /* compatibility */
void *shm_unused2; /* ditto - used by DIPC */
void *shm_unused3; /* unused */
};
attaches描述被共享的物理内存对象所映射的各进程的虚拟内存区域。每一个希望共享这块内存的进程都必须通过系统调用将其关联(attach)到它 的虚拟内存中。这一过程将为该进程创建了一个新的描述这块共享内存的vm_area_struct数据结构。创建时可以指定共享内存在它的虚拟地址空间的 位置,也可以让Linux自己为它选择一块足够的空闲区域。
这个新的vm_area_struct结构是维系共享内存 和使用它的进程之间的关系的,所以除了要关联进程信息外,还要指明这个共享内存数据结构shmid_kernel所在位置; 另外,便于管理这些经常变化的vm_area_struct,所以采取了链表形式组织这些数据结构,链表由attaches指向,同时 vm_area_struct数据结构中专门提供了两个指针:vm_next_shared和 vm_prev_shared,用于连接该共享区域在使用它的各进程中所对应的vm_area_struct数据结构。
- 大小: 7 KB
- 大小: 25.7 KB
分享到:
相关推荐
Linux进程间通信的共享内存是一种高效的数据交换方式,但是对共享内存的访问同步控制需要程序员自己实现,这是在使用共享内存时需要注意的问题。通过上述步骤和示例程序的学习,我们可以更好地理解共享内存的工作...
本示例中提到的“linux无亲缘关系进程间通信”着重讲解了如何利用互斥锁(Mutex)、条件变量(Condition Variable)以及共享内存(Shared Memory)这三种机制来实现非父子进程间的同步通信。 1. **互斥锁**:互斥锁...
### Linux通过共享内存实现进程之间的通信 #### 一、概述 共享内存作为一种高效的过程间通信(IPC)方式,允许多个进程直接访问同一段物理内存。这种方法的优势在于减少了数据复制的开销,使得进程间的数据交换更为...
Linux 下 C 语言编程使用共享内存实现进程间通信 共享内存是 Linux 操作系统中的一种进程间通信机制,它允许不同的进程访问同一个内存区域,从而实现进程间的数据交换。在 C 语言中,使用共享内存可以通过 shmget、...
### Linux共享内存实现进程间通信详解 #### 一、引言 在Linux系统中,进程间的通信(Inter-Process Communication, IPC)是一项重要的技术,它允许...希望本文能帮助读者更好地理解和掌握Linux下的共享内存通信机制。
Linux环境进程间通信(五) 共享内存(上)
在Linux中,可以使用`shmget`函数创建共享内存,`shmat`将其映射到进程地址空间,`shmdt`用于取消映射,而`shmctl`则进行控制操作,如删除或调整大小。 1. **创建共享内存**:使用`shmget(key, size, flags)`,其中...
linux c 进程间通信 共享内存的操作 源代码
本示例代码着重于使用共享内存和信号量来解决进程间的通信和同步问题,这是一种高效且灵活的方法,特别是在多处理器和多线程环境中。下面我们将详细探讨这些概念以及它们在Linux系统中的实现。 **共享内存** 是一种...
Linux 下C++共享内存、信号量封装,实现进程同步
linux进程间通信编程之共享内存实例程序。
通过理解这个示例,开发者可以掌握Linux下多进程通信的基本技巧,并能够应用于更复杂的应用场景,如数据库并发控制、分布式系统等。熟练掌握信号量和共享内存,将有助于提高系统的并行性和效率。
总结来说,互斥锁、条件变量和共享内存是Linux下实现进程间通信的关键工具,它们共同确保了多进程环境下的数据安全和程序的正确执行。通过合理地使用这些工具,开发者能够构建出高效且可靠的多进程应用程序。在实际...
在 Linux 中,进程通信可以通过信号、管道和共享内存等方式实现。 一、信号机制 在 Linux 中,信号是一种异步通信机制,允许一个进程向另一个进程发送信号,从而通知其执行某些操作。信号可以分为两类:内核信号和...
Linux_进程间通信_-_共享内存shmget方式
之前用过Prosix版本的共享内存和信号量,一直没有实践System V版本的,主要是因为其信号量集的概念操作有些复杂,今天试着写一个SV版本的共享内存进程间通信,使用信号量同步。程序提供了几个简单的用于操作SV版本...
- **共享内存(Shared Memory)**:共享内存是最有效的进程间通信方法之一,它允许多个进程共享一块内存区域,从而实现数据的高效交换。 ##### Linux系统中的同步机制 在Linux系统中,由于多个进程共享内核空间,...
linux下C语言编程4-使用共享内存实现进程间通信.pdf
**8.1 Linux下进程间通信概述** Linux的进程通信机制源自UNIX,融合了AT&T的System V IPC和BSD的套接字机制。UNIX IPC主要包括管道、FIFO和信号,System V IPC涉及消息队列、信号量和共享内存,而Posix IPC对应Posix...