概述
共享内存是进程间通信最简单的方式之一,是在两个独立的进程用户地址空间中映射到同一块物理内存,因为数据字节由内存映射到用户空间,所以它也是进程通信最快的IPC方式。但是由于内核没有提供对访问共享内存进行同步,所以需要我们自己实现同步机制,一般是使用信号量。
所以一般操作模型是:
获取mutex,锁定共享内存。
将要通信的数据写入(读取)共享内存。
释放mutex。
共享内存原理图:
共享内存相关函数
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int semget(key_t key, int size, int flag);
void *shmat(int shmid, void *addr, int flag);
int shmdt(void *addr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
1、 ftok() 获得一个key
key_t ftok(const char *pathname, int proj_id);
pathname:一定要在系统中存在并且进程能够访问的;
proj_id:一个1-255之间的一个整数值,典型的值是一个ASCII值;
2、shmget 创建共享内存
int shmget(key_t key ,int size,int shmflg)
成功返回一个共享内存标识符,失败返回-1
key:一个用来标识共享内存块的键值(一般由ftok产生)
size:指定了所申请的内存块的大小
shmflg:操作共享内存的标识,IPC_CREAT, IPC_EXCL 的按位或
3、shmat 连接共享内存
void *shmat(int shm_id, const void *addr, int shmflg) ;
成功返回共享存储段连接的实际地址,失败返回-1
shm_id:为shmget返回的共享内存标识符。
addr:指明共享内存段要连接到的地址(进程空间内部地址),通常指定为空指针,表示让系统来选择共享内存在进程地址空间中出现的地址。
shmflg:可以设置为两个标志位(通常设置为0)
SHM_RND( 表示第二个参数指定的地址应被向下靠拢到内存页面大小的整数倍)
SHM_RDONLY:是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式
4、shmdt 分离共享内存
int shmdt(const void *shmaddr) ;
成功时返回0。失败时返回-1。
shmaddr:共享内存的起始地址
5、shmctl 控制共享内存
int shmctl( int shmid , int cmd , struct shmid_ds *buf );
返回值: 成功:0 失败:-1
shm_id:为shmget返回的共享内存标识符。
cmd:控制命令
buf:一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定
其中cmd的取值如下
cmd | 描述 |
---|---|
IPC_STAT | 得到共享内存的状态 |
IPC_SET | 改变共享内存的状态 |
IPC_RMID | 删除共享内存 |
其他关于ipc的命令
ipcs、ipcmk和ipcrm
共享内存通信示例程序
写端程序
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int count = 0;
key_t key=ftok(".","m");
if(key < 0)
{
perror("ftok error!!!\n");
return -1;
}
int shmid = shmget(key,4096,IPC_CREAT|IPC_EXCL|0666);
if(shmid < 0)
{
perror("shmid error!!\n");
return -2;
}
sleep(5);
char *buf = shmat(shmid, NULL, 0);
while(count<4096)
{
buf[count] = 'A'+count%26;
sleep(2);
count++;
buf[count] = '\0';
}
shmdt(buf);
sleep(5);
DestoryShm(shmid);
return 0;
}
读端程序
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int count = 0;
key_t key=ftok(".","m");
if(key < 0)
{
perror("ftok error!!!\n");
return -1;
}
int shmid = shmget(key,4096,IPC_CREAT);
if(shmid < 0)
{
perror("shmid error!!\n");
return -2;
}
sleep(5);
char* buf = shmat(shmid, NULL, 0);
while(1)
{
printf("%s\n", buf);
sleep(2);
}
shmdt(buf);
return 0;
}