对于linux来讲,不同进程之间的内存是不能读写的,一个进程只能读写自己所属的内存。A进程是不能读写B进程内存的?如果程序确实想通过内存交换数据怎么办?linux提供共享内存机制。共享内存是由内核处于多个进程间交换信息的目的而留出的一块内存区(段)。共享内存也需要设置相关权限的。这段内存空间可以由需要访问的进程将其映射到自己的私有地址空间。如果一个进程更新了段中数据,其他进程也能立即看到更新。因为系统内核没有对访问共享内存进行同步,您必须提供自己的同步措施。例如,在数据被写入之前不允许进程从共享内存中读取信息、不允许两个进程同时向同一个共享内存地址写入数据等。解决这些问题的常用方法是通过使用信号量进行同步。
如下图所示:
进程a数据进程b是无法读取的,进程b数据进程a也是无法读取的。共享内存在内存中是一个单独的内存段,进程a和进程b都不能直接读。进程自己有一个内存段,和共享内存段之间有一个对应关系,进程每一次在内存段写的数据,操作系统会把进程内存段数据自动同步到共享内存区域。
使用共享内存
1. 类似管道一样,要使用共享内存必须先创建共享内存。使用shmget()函数。
2. 映射共享内存到具体的进程空间。使用shmat()函数进行映射。撤销映射有shmdt().
相关函数说明:
shmget()函数:
所需要的头文件:man 2 shmget 中查看
#include <sys/ipc.h>
#include <sys/shm.h>
#include<sys/types.h>
函数原型:int shmget(key_t key,int size,int shmflag)
函数传入值:
key 共享内存的键值,多个进程可以通过它访问一个共享内存。通常用特殊常量IPC_PRIVATE作为键值可以保证系统建立一个全新的共享内存块。
size:共享内存区域大小
shmflg:同open 函数权限位,也可以用八进制表示,如0666.
函数返回值:成功返回共享内存标识,出错返回-1。
shmat() 函数
所需头文件同上。
函数原型:char * shmat(int shmid,const void *shmaddr,int shmflg)
函数传入值:
shmid 要映射的共享内存标识符
shmaddr:将共享内存映射到的地址(为0则表示系统自动分配内存)
shmflg 默认0 表示可读可写,SHM_RDONLY 表示只读。
返回值:成功返回被映射的地址,出错返回-1.。
函数 int shmdt(const void *shmaddr)撤销映射有shmdt().共享内存创建成功后可以通过ipcs -m 命令查看。当然也可以使用ipcrm -m shmid 删除对应共享内存。
程序说明:
分别执行./main 1 执行./main 2 后shmid 是通过程序获得的。是通过和键值对应关系获得的。因为两次执行程序key一样,再一次执行程序时候会返回errno为存在错误码,
shmid = shmget(key, 0, 0);//由此或得已经存在的共享内存shmid
int shmid = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0666);//注意这里写法
shmget(IPC_PRIVATE,1024,0666);//这种方式都会新建一个共享内存
/*
* main.c
*
* Created on: 2015-1-29
* Author: hsc
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <errno.h>
#define SHMSIZE 1024
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("usage:1 表示写共享内存,2 表示读共享内存!\n");
return 0;
}
char *shmaddr;
int key; //共享内存的键值
// 通过ftok 函数得到一个键值
//这里.表示当前目录 ftok就是通过文件or目录的索引节点号和id(这里1)组合成的key
key = ftok(".", 1);
printf("key %d \n", key);
int shmid = shmget(key, SHMSIZE, IPC_CREAT | IPC_EXCL | 0666);
if (-1 == shmid) //如果key 不存在
{
if (errno != EEXIST)
{
printf("%s \n", strerror(errno));
return -1;
}
}
<pre name="code" class="cpp"> shmid = shmget(key, 0, 0); //通过key 获取shmid
if (shmid == -1)
{
printf("%s \n", strerror(errno));
return -1;
}
printf("shmid is %d \n", shmid);shmaddr = shmat(shmid, 0, 0); //映射到共享内存if (shmaddr == (void *) -1){printf("%s \n", strerror(errno));return -1;}if (atoi(argv[1]) == 1){strcpy(shmaddr, "hello");printf("write success!\n");}if (atoi(argv[1]) == 2){printf("share memory:%s \n", shmaddr);}if (shmdt(shmaddr) < 0) //解除映射{printf("%s \n", strerror(errno));return -1;}return 0;}