1.共享内存
1.共享内存是一种最为高效的进程间通信方式。因为进程可以直接读写内存,而无须创建任何形式的载体即可完成数据的传递。共享内存的通信原理,与进程的虚拟地址空间映射息息相关。共享内存就是内存共享。多个进程通过访问同一块内存区域,来实现数据的交互。
2.一般情况下,每个进程都享有自己的独立的虚拟内存空间,因此不同的进程所映射的物理内存也不相同。而共享内存的通信原理,则刚好是将一块实际的物理内存空间,分别映射到不同进程的虚拟地址空间上,这样进程只需要关注映射属于自己的虚拟地址即可,其访问的空间则为同一块空间。
3.这样的操作虽然很高效,但也有缺陷。因为多个进程同时访问同一共享的资源,则会产生竞态,从而导致数据的不确定性。这一点与多线程通信是一样的。因此共享内存这种通信机制基本不能单独使用,而是需要结合一定的同步互斥机制,保证数据的访问不会出现问题。共享内存的通信原理如图所示。

2.共享内存实现步骤
共享内存的实现很简单,
第一步,需要获得一块共享内存段;
第二步,将创建的共享内存段映射到不同的进程空间上,便可直接访问;
第三步,如果当前进程不需要访问该共享区域,则选择进行断开映射处理;
第四步,当不需要使用共享内存时,则选择释放共享内存段。
要使用共享内存,应该有如下步骤:
1.开辟一块共享内存 shmget() //创建或打开共享内存段。
2.将共享内存段映射到进程的虚拟地址空间上。 shmat()
3.写入/读出strcpy(),strncpy(),memcpy()
4.解除本进程使用这块共享内存映射shmdt()
5.删除这块共享内存 shmctl()或者命令行下ipcrm
3.共享内存的函数 (看代码,函数的介绍不用仔细看)
shmget--创建共享内存函数
头文件:#include
#include
函数原型:int shmget(key_t key, size_t size, int shmflg);
参数: key标识共享内存的键值: 0/IPC_PRIVATE。 当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。size 共享储存器区段的大小,size是要建立共享内存的长度。所有的内存分配操作都是以页为单位的。shmflg建立标志和储存权限,包括IPC_CREAT和IPC_EXCL IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。 IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误
返回值为共享内存的标识符;不成功返回-1,errno储存错误原因。
4.shmat--共享内存段映射到进程地址空间
头文件:#include
#include
函数原型:void *shmat(int shmid, const void *addr, int flag);
参数:shmid:共享存储器标识, addr:共享存储段连接到调用进程的哪个地址上与addr参数以及在flag中是否指定SHMRND位有关。
(1) 如果addr为0,则此段连接到由内核选择的第一个可用地址上。
(2) 如果addr非0,并且没有指定SHMRND,则此段连接到addr所指定的地址上。
(3) 如果addr非0,并且指定了SHMRND,则此段连接到( a d d r-(addr mod SHMLBA))所表示的地址上。SHMRND命令的意思是:取整。SHMLBA的意思是:低边界地址倍数,它总是2的乘方。该算式是将地址向下取最近1个 SHMLBA 的倍数。
flag可为: SHM_RND 如果addr不为NULL,将会进位到最低可用SHMLBA地址。 SHM_RDONLY 共享区段以只读的方式映射到进程的地址空间。 SHM_REMAP 如果本标志被指定,意味着替代掉与指定参数重叠的现存共享区段的映射。
返回值:如果成功,返回共享存储段地址,出错返回-1
5.shmdt--解除进程对共享内存区域的映射
头文件:#include
#include
函数原型:int shmdt(const void *shmaddr)
参数:shmaddr为调用shmat函数后获得的地址指针
返回值:该函数并没有删除共享内存段。调用成功返回0,失败返回-1
6.shmctl--实现对共享内存区域的控制操作
头文件:#include
#include
函数原型:int shmctl(int shmid , int cmd , struct shmid_ds *buf);
参数:shmid 共享区段的标识码,buf指向shmid_ds结构变量的指针,
cmd的合法命令如下:
IPC_STAT 将现在的共享存储器状态拷贝一份存入buf指向的结构中。
IPC_SET 设定共享存储器的用户识别码,使用群识别码及共享存储器的存取权限
IPC_RMID 将共享存储器标记成需要释放,实际的释放工作由最后一个与该共享区段脱连的进程实施。
IPC_INFO 获得系统共享内存的限制和相关参数,将其保存在buf参数指向的内存空间中。SHM_INFO 获得系统共享内存消耗的系统资源信息,将其保存在buf参数指向的内存空间中。
buf为指向shm_info结构体的指针,与shminfo类似,该结构体定义于
SHM_STAT 获取如IPC_STAT一样的信息。但参数shmid并非共享区段识别码,而是维持所有共享区段信息的内核内部数组索引。
SHM_LOCK 防止共享区段交换出内存。
SHM_UNLOCK 解除已锁定的共享区段,允许共享区段可交换。
注意:共享内存不会随着程序结束而自动消除,要么调用shmctl删除,要么自己用手敲命令去删除,否则永远留在系统中。
7.代码:
- /************************************************************************************************************************************************************************************************************************
- *文件名:
- *作 者:She001
- *时 间:
- *版 本:
- *作 用:共享内存 的函数 与运用
- ****************************************************************************************************************************************************************************************************************************/
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- //share memory 进程中的共享内存的使用方法
- //1.申请内存
- //2.映射
- //3.一个进程向 向共享内存中写入数据
- //4.一个进程向 共享内存中读取数据
- //5.解除映射
- //
-
- int main(int argc,char *argv[])
- {
- //创建共享内存
- int shmid = shmget(IPC_PRIVATE,1024,IPC_CREAT|0664);
- printf("shmid =%d\n",shmid);
-
- //打开映射
- char * shstr = shmat(shmid ,0,0);
- if(shstr==NULL)
- {
- perror("shstr error\n");
- return -1;
- }
- //写
- char buff[200]="this is thursday";
- strcpy(shstr,buff);
-
- //读
- char buff2[200]="";
- strncpy(buff2,shstr,10);
- printf("buff2 =%s\n",buff);
-
-
- //解决映射
- shmdt(shstr);
-
- //删除共享内存
- shmctl(shmid,IPC_RMID,0);
- system("ipcs -m ");
-
-
- return 0;
-
- }