~共享内存概述:
共享内存,就是允许两个或者多个不同的进程访问同一个给定的内存,因为数据不需要在进程复制,所以共享内存是最快的一种IPC,不同的进程将同一段物理地址映射到各自的进程中,如果一个进程向共享内存写数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。
~注:当一个进程在共享内存处写入数据时不应该别的进程去读(共享内存不提供同步机制)。
~注:它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
1,共享内存相关的API
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);//获取共享内存
//参数1:系统使用共享内存时必须有ID号(用ftok获取)
//参数2:龚翔内存空间(以1024byte为单位);
//参数3:一般为IPC_CREAT|0600创建一个键值和key相等的可读可写的内存
void *shmat(int shmid, const void *shmaddr, int shmflg);//将共享内存映射到改进程的地址空间中
//参数1:共享内存的标识符(ID)
//参数2:指定共享内存出现在进程内存地址的什么位置
//参数3:SHM_RDONLY读只读模式其他为读写
int shmdt(const void *shmaddr);//禁止共享内存连接到进程地址空间
int shmctl(int shmid, int cmd, struct shmid_ds *buf);//对共享内存进行移除等控制
//参数1:shm_id是shmget函数返回的共享内存标识符。
//参数2:command是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
//参数3:buf是一个结构指针,它指向共享内存模式和访问权限的结构。
shmid_ds结构至少包括以下成员:
2,共享内存简单的代码实现;
read.c文件用于读共享内存数据,write.c用于往共享内存中写数据(写入hello world!)。
write.c文件如下:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int shmid;
key_t key;
key = ftok(".",1);
char *shmaddr;
shmid = shmget(key,1024*6,IPC_CREAT|0666);//创建或者得到一个键值与key相等的共享内存ID号
if(shmid == -1)
{
printf("shmget failed!\n");
exit(0);
}
shmaddr = shmat(shmid,0,0);//映射共享内存地址到该进程的地址空间
strcpy(shmaddr,"hello world!");
sleep(5);//等待5s让别的进程读取内存数据
shmdt(shmaddr);//和该进程解除地址映射
shmctl(shmid,IPC_RMID,0);//删除共享内存,不关心它的删除返回值
read.c文件代码如下:
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int shmid;
key_t key;
key = ftok(".",1);
char *shmaddr;
shmid = shmget(key,1024*4,0);//在write.c文件中已经得到了键值与key相等的共享内存所以不需要创建
if(shmid == -1)
{
printf("shmget failed!\n");
exit(0);
}
shmaddr = shmat(shmid,0,0);
printf("shmat ok!\n");
printf("data = %s\n",shmaddr);
shmdt(shmaddr);
return 0;
}
注:先让write.c先写入共享内存,然后read.c去读,保证在5秒内不然read会报错(在write执行5秒后移除了共享内存)
注:IPC中键值的作用:
进程间的通讯,必须要有个公共的标识来确保使用同一通讯通道(比如通道为共享内存),然后再把这个标识与某个共享内存进行绑定,任何一个进程如果使用相同一个标识,则内核就可以通过标识来找到对应的那段共享内存,这个标识就是键值。如果没有键值,一个进程打开或者创建一个共享内存并返回ID,但是其他想要通信的进程不知道这个共享内存的ID是多少,所以就不能通讯了。
命令扩展
ipcs -m//查看共享存储段
ipcrm -m [shmid]//删除系统共享存储段