我们都知道,多线程与多进程都可以访问共享内存;但是二者访问的共享内存是有区别的,是不一样的。多个线程可以由同一进程产生,它们共享同一进程的地址空间,如果这些线程需要访问同一块内存空间,定义一个全局变量就可以满足;但多个进程之间的地址空间是相互独立的,如果多进程需要访问同一块内存,则不能使用全局变量,必须使用共享内存,而且共享内存是多进程间信息共享与交换最高效的方式。

共享内存针对多进程的访问并未提供锁机制,是允许多个任意进程(不要求具有父子关系)访问同一块内存空间的。进程可以将共享内存链接到自己的地址空间进行使用处理,也就是说如果进程A修改了共享内存中的某个变量值,进程B读取到该变量的值可能就是已经修改过的。在一个进程访问共享内存的同时,不会阻止其他进程对该共享内存的读写。为了防止整个世界处于混乱的状态,还好聪明的操作系统提供了信号量实现进程间同步,使得多进程访问共享内存时实现加锁的操作。

下面几个函数都是用于操作共享内存的:

Function-shmget

int shmget(key_t key, size_t size, int shmflg);    linux下查询该函数   man shmget

java多个代码块共享变量加锁 java多进程共享内存_java多个代码块共享变量加锁

功能:该函数用于获取/创建(如果不存在,则创建)共享内存

key: 共享内存的键值,一般用十六进制数表示;不同共享内存的key值是不一样的

size: 待创建共享内存的大小,单位为 byte

shmflg: 共享内存的访问权限,和文件权限差不多一个意思理解,比如设置该值为  0666|IPC_CREAT, 表示全部用户对它可读(r,4)可写(w,2),(注意 0666 是八进制数,前面的0不能省略); 而且 IPC_CREAT 则表示,如果该共享内存不存在就创建它,如果没有这个宏出现,则只能获取已经存在的共享内存,不会创建不存在的。

返回值:成功--放回该共享内存的id(一个大于0的整数),失败--返回-1(导致失败原因一般有二:系统内存本身不够用;没有权限)
shmget函数使用示例代码如下,运行之后可使用  ipcs -m  命令查看系统共享内存:

java多个代码块共享变量加锁 java多进程共享内存_c++_02

java多个代码块共享变量加锁 java多进程共享内存_共享内存_03

如果共享内存的key使用十进制数也可以,但是一般不推荐这么使用(也是有一定的道理)

java多个代码块共享变量加锁 java多进程共享内存_shmat_04

java多个代码块共享变量加锁 java多进程共享内存_shmget_05

十进制1024对应十六进制0x400

共享内存一般使用程序进行创建或删除,也可以手动使用命令 ipcrm -m shmid 进行删除

Function-shmat

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

java多个代码块共享变量加锁 java多进程共享内存_c++_06

功能:该函数用于把共享内存连接到当前进程的地址空间中;

shmid:  该参数由函数shmget()返回;

shmaddr: 指定共享内存连接到当前进程中的地址位置,通常填0,表示让系统自己选择共享内存的连接地址;

shmflg: 标志位,通常填0;

返回值:成功--返回共享内存起始地址,失败--返回(void*)-1

Function-shmdt

int shmdt(const void *shmaddr);   man shmdt

java多个代码块共享变量加锁 java多进程共享内存_c++_07

功能:该函数用于将共享内存从当前进程中分离出去,相当于 shmat 的反向操作

shmaddr: shmat()函数返回的地址;

返回值:成功--0,失败-- -1

shmat函数与shmdt函数的示例代码如下,以及代码测试结果:

java多个代码块共享变量加锁 java多进程共享内存_shmat_08

java多个代码块共享变量加锁 java多进程共享内存_shmat_09

java多个代码块共享变量加锁 java多进程共享内存_共享内存_10

(注意:在使用 shmat 函数连接共享内存到当前进程后,需要与 (void*)-1 进行判断是否成功,而不仅仅是与-1进行判断)

Function-shmctl 

int shmctl(int shmid, int cmd, struct shmid_ds *buf);  man shmctl

java多个代码块共享变量加锁 java多进程共享内存_shmget_11

功能:该函数用于操作共享内存,最常用的操作是删除共享内存

shmid: shmget函数返回的共享内存id

cmd:操作共享内存的指令,若需要删除,则填 IPC_RMID

buf:操作共享内存的数据结构地址,如果需要删除共享内存,则填0就行

返回值:成功--0,失败-- -1

该函数示例代码及运行结果如下:

java多个代码块共享变量加锁 java多进程共享内存_java多个代码块共享变量加锁_12

java多个代码块共享变量加锁 java多进程共享内存_shmget_13

敲黑板:共享内存的数据结构中只能使用c/c++内置的数据类型,不能使用STL容器(STL会在堆区动态分配内存,这部分内存不属于共享内存),如果将刚才的结构体中的 cname 变量改为 string,则运行程序会报错。

java多个代码块共享变量加锁 java多进程共享内存_共享内存_14

java多个代码块共享变量加锁 java多进程共享内存_c++_15

以上为关于共享内存的基础处理及使用方法,共勉。