添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

1. 前言

共享内存是进程间通信的方式之一,且也是最为高效的通信方式。在32位的Linux系统上,每一个进程都有自己独立的3GB用户空间,这3GB空间中其中有一部分是内存映射区域,而共享内存也是在此发挥了它的作用。假设有两个进程,共享内存则将其内存空间分别映射到两个进程的地址空间中,这样两个进程操作共享内存就像操作自己的地址空间一样,共享内存中的数据变化会影响到双方,例如某个进程向共享内存写入数据,另一个进程可以从共享内存读出数据。

2. 共享内存API介绍

在Linux上提供了一组相关的API使用共享内存。这些接口的声明都在#include <sys/shm.h>以及在#include <sys/ipc.h>中声明的用于获取键值的接口。接下来就来一一介绍一下这些API的含义。

ftok函数
函数原型:

key_t ftok(const char *pathname, int proj_id);

别纠结ket_t是什么类型,实际上是int型的别称。pathname是一个指定的文件名,该文件必须存在且可访问。proj_id可以随意设置,在linux上他的值在1-255之间随意取值即可。
这个函数是什么作用呢?要知道在使用共享内存时,首先需要创建一个文件来充当共享内存,但是在系统中可能存在许许多多这样的文件,所以需要唯一一个编号来标志一个个这样的文件。ftok正是根据文件inode和proj_id来产生一个唯一的编号来表示一个共享内存。

shmget函数
函数原型:

int shmget(key_t key, size_t size, int shmflg)

该函数的作用是创建一个共享内存对象并返回共享内存标识符,如果系统中已经有与当前key相等的共享内存对象,则直接返回共享内存标志符。
参数说明:
key为ftok产生的键值
size为新建共享内存的大小,以字节为单位。
shmflag表示创建的共享内存的操作权限,shmflag为0表示:取共享内存标识符,若不存在则函数会报错;shmflag为IPC_CREAT表示如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符。shmflag为IPC_EXCL时表示如果存在这样的共享内存则报错。
返回值:返回共享内存标识符,出错返回-1。

shmat函数
函数原型:

void *shmat(int shmid, const void *shmaddr, int shmflg)

该函数将共享内存对象映射到调用进程的地址空间中,连接成功后会返回共享内存在地址空间中的首地址。
参数说明:
shmid:由shmget函数得到的共享内存对象标识符,指定将哪个共享内存对象映射到地址空间中。
shmaddr:表示共享内存对象从进程空间的哪个地址开始映射,一般为NULL,表示让内核选定一个合适的地址即可。
shmflg:共享内存的读写权限,SHM_RDONLY表示只读模式,其他为读写模式。

shmdt函数
函数原型:

int shmdt(const void *shmaddr);

该函数是将共享内存与该进程分离,分离后该进程的地址空间就没有共享内存部分,也不能对共享内存进行操作。注意,共享内存与进程分离后,共享内存还是存在的,系统中的进程依旧可以将共享内存映射到自己的地址空间中。
参数说明:
shmaddr: 该地址是shmat函数返回的地址,表示共享内存的首地址。

shmctl函数
函数原型:

int shmctl(int shm_id, int cmd, struct shmid_ds *buf);

该函数用于对共享内存进行控制,最常见的莫过于删除共享内存了。
参数说明:
shm_id: 由shmget返回的共享内存标志符。
cmd: 表示对共享内存的操作,该变量有三个取值:

// cmd的取值含义:
1. IPC_RMID:删除共享内存
2. IPC_STAT:得到共享内存的状态,buf用于存储共享内存的shmid_ds结构
3. IPC_SET:改变共享内存的状态,把buf中的结构体赋值给本共享内存的shmid_ds结构体

3. 简单的小实例

接下来通过一个小小的例子,来看看如何使用共享内存实现进程间通信。该例子有两个进程,write进程写五个数据到共享内存,read进程从共享内存读取这五个数。
具体实现如下:
write.cpp

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
const char* path = "/usr/IPC";
int main()
	int data[5] = {1,2,3,4,5};
	int i = 0;
	key_t key;
	int shmId;
	key = ftok(path, 1); //为共享内存生成键值
	if(key == -1)
		cout << "ftok failed" << endl;
	shmId = shmget(key, 100, IPC_CREAT|IPC_EXCL | 0600); //获取共享内存标志符
	cout <<"shmId=" << shmId << endl;
	if(shmId == -1)
		cout << "shmget failed" << endl;
	int* shmaddr = (int*)shmat(shmId, NULL, 0); //获取共享内存地址
	for(i = 0; i < 5; i++)
	//往共享内存写数据
		*shmaddr = data[i];
		shmaddr++;
	cout << "write end" << endl;
	return 0;

读进程如下:
read.cpp

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
const char* path = "/usr/IPC";
int main()
	key_t key;
	int shmId;
	int i = 0;
	key = ftok(path, 1);//生成键值
	if(key == -1)
		cout << "ftok failed" << endl;
	shmId = shmget(key, 0, 0);
	cout << "shmId=" << shmId << endl;
	if(shmId == -1)
		cout << "shmget failed" << endl;
	int* shmaddr = (int*)shmat(shmId, NULL, 0); //获取共享内存地址
	for(i = 0; i < 5;i++)
	//从共享内存读取数据
		cout << *shmaddr << endl;
		shmaddr++;
	cout << "read end" << endl;	

实验结果如下:结果如预期。

上例中没有使用shmctl删除共享内存,可以在终端执行ipcrm -m + shmid来删除指定的共享内存。

4. 总结

通过上面的小例子可以看出,简单的共享内存创建和使用流程如下:
1.ftok函数为共享内存生成键值
2.shmget函数获取共享内存的唯一标志符。
3.shmaddr函数获取共享内存的映射到地址空间后的首地址。
4.shmdt函数将进程与共享内存分离(上例未体现)
5.shmctl函数删除共享内存(上例未体现)
另外,不得不提的是,共享内存本身提供同步机制,一般在多进程的共享内存使用过程中都会使用信号量实现同步操作。

Linux‘ C/C++ 共享内存配合消息队列+信号量下的封装 我所做的服务端demo中分为前置与后置两个服务器,前置做接收信息、发包与解包等处理,后置则包业务的处理,前后置分为两个进程运行,那么彼此要接收到互相发送的信息必然少不了Linux下进程间的通信,而我对共享内存的主要封装思路如下: 现有共享内存A端与B端,两者为同一个共享内存,一个写一个读 创建一个信号量,来实现可读资源与可写资源的P V操作,充当共享内存读写中的缓冲机制 创建一个消息队列, A端共享内存写入后,则往该消息队列发送消 共享内存用于实现进程间大量的数据传输,共享内存是在内存中单独开辟一段内存空间,这段内存空间有自己特有的数据结构,包括访问权限、大小和最近访问时间等。返回值:(1)成功,返回共享内存标识符(2)出错,返回-1,错误原因存于errno中。shmflag: 指定共享内存的访问权限和映射条件,一般设置为0,即读写权限。返回值:成功:0,出错:-1,错误原因存在于errno中。返回值:成功:0,出错:-1,错误原因存在于errno中。参数:shmaddr:指定共享内存的映射地址。作用:共享内存的内存管理。 一、共享内存 共享存储允许两个或多个进程共享一给定的存储区。因为数据不需要在客户机和服务器之间复制,所以这是最快的一种 I P C。使用共享存储的唯一窍门是多个进程之间对一给定存储区的同步存取。若服务器将数据放入共享存储区,则在服务器做完这一操作之前,客户机不应当去取这些数据。通常,信号量被用来实现对共享存储存取的同步。 #include<sys/ipc.h> #include<sys/shm.j> int shmget(key_t 之前写了个项目的demo,windows平台下python实现的,由于效率问题,用了多进程,进程间的通讯是依赖于multiprocessing manager. 前段时间,突然说要把项目移植到Liunx平台下,而且要用c++来实现。(我直接晕过去了,这和重写一遍有什么区别? 遇到的第一个问题就是怎么解决进程间通信,百度之后决定使用共享内存。因为大家都说它的效率最快。 我用的是shm,关于它的介绍有很多,我这里就不解释了。 server.cpp ,往内存里写,int flag起到一个读写保护的作用,可 欢迎转载请注明出处:海漩涡http://blog.csdn.net/tanhuifang520linux 进程通信之共享内存机制C++代码实例一、使用说明只需包含share_memory.h使用类通过名称和内存大小参数与其他进程共同使用一段内存二、代码实例1、通用类实现share_memory.h#ifndef __SHAREMEMORY_H__ #define __SHAREMEMORY_H__... 1. 什么是共享内存    共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。 文章目录1、1.1、ShareMemory.h1.2、ShareMemory.cpp1.3、SecKeyShm.h1.4、SecKeyShm.cpp1.5、main.cpp 1.1、ShareMemory.h #pragma once #include <sys/ipc.h> #include <sys/shm.h> const char RandX = 'x'; class ShareMemory public: ShareMemory(int key);// 共享内存是一种进程间通信的方式,速度比较快 基本原理:以页面为单位,将一个普通文件映射到内存中,达到共享内存和节约内存的目的,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能 windows和linux都提供了原生的系统级的C++接口,可以将文件映射到内存 windows中使用CreateFileMapping linux使用mmap 这里...