什么是共享内存?
共享内存顾名思义就是:两个不同的进程之间共享同一块内存。共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址。
从上面这张图中我们可以看出,共享内存其实是两个进程通过各自的地址空间加页表的映射,映射到同一块物理内存区域,而通过在这个公共的内存区域读数据和写数据,从而实现了进程间的通信。
而共享内存共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读取。所以我们要通过信号量来实现同步和互斥。
共享内存的实现接口:
(1)、shmget(得到一个共享内存标识符或创建一个共享内存对象)
int shmget(key_t key, size_t size, int shmflg)
参数:
key: (IPC_PRIVATE):会建立新共享内存对象大于的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值
size: 大于0的整数:新建的共享内存大小,以字节为单位。
shmflg:取共享内存标识符,若不存在则函数会报错。
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存
如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT | IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共
享内存则报错。
返回值:成功返回共享内存的标识符,失败返回-1。
(2)、shmat(把共享内存区对象映射到调用进程的地址空间)
void *shmat(int shmid, const void *shmaddr, int shmflg)
参数:
shmid :共享内存标识符。
shmaddr : 指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置。
shmflg :SHM_RDONLY:为只读模式,其他为读写模式。
shmaddr : 指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置。
shmflg :SHM_RDONLY:为只读模式,其他为读写模式。
返回值:成功返回附加好的共享内存地址,失败返回-1,错误原因存于error中。
(3)、shmdt(断开共享内存连接)
int shmdt(const void *shmaddr)
参数:
shmaddr:连接的共享内存的起始地址函数返回值:成功:0出错:-1,错误原因存于error中。
(4)、shmctl(共享内存管理)
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
参数:
shmid :共享内存标识符
cmd :
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存。
buf : 共享内存管理结构体。
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存。
buf : 共享内存管理结构体。
在命令行上查看共享内存的命令:
ipcs -m
共享内存的删除
ipcrm -m shmid
1、共享内存是所有进程间通信访问最快的,省略了两次数据的拷贝(相对管道)。
2、不带任何同步互斥机制。
3、共享内存的生命周期随内核。
以下是代码实现部分
从上图中我们可以看出 ipcs -m 是查看系统中的共享内存,而688143就是我们刚才创建的,在运行server之后要ctrl+c,因为要是server正常退出后就会销毁共享内存,而ipcrm -m [shmid]这里的shmid也就是688143,删除了在系统中的共享内存。
"comm.h"
#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#define pathname "."
#define PROJ_ID 0x6666
#define SIZE 4095
int createShm();
int getShm();
int destroytshm(int shmid);
#endif
"comm.c"
#include "comm.h"
static int commShm(int size, int flag)
{
key_t _key = ftok(pathname, PROJ_ID);
if(_key < 0)
{
perror("ftok");
return -1;
}
int shmid = shmget(_key, size, flag);
if(shmid < 0)
{
perror("shmid");
return -2;
}
return shmid;
}
int createShm()
{
return commShm(SIZE, IPC_CREAT|IPC_EXCL|0666);
}
int getShm()
{
return commShm(SIZE, IPC_CREAT);
}
int destroyShm(int shmid)
{
if(shmctl(shmid, IPC_RMID, NULL) < 0)
{
perror("shmctl");
return -1;
}
return 0;
}
"server.c"
#include "comm.h"
int main()
{
int shmid = createShm();
char* buf;
buf = shmat(shmid, NULL, 0);
sleep(5);
int count = 0;
while(count < 26)
{
buf[count++] = 'a' + count;
buf[count] = 0;
sleep(1);
}
shmdt(buf);
destroyShm(shmid);
return 0;
}
"clinet.c"
#include "comm.h"
int main()
{
int shmid = getShm();
char* buf;
buf = shmat(shmid, NULL, 0);
int count = 0;
while(count++ < 15)
{
printf("clinet# %s\n", buf);
sleep(1);
}
shmdt(buf);
return 0;
}
从上图中我们可以看出 ipcs -m 是查看系统中的共享内存,而688143就是我们刚才创建的,在运行server之后要ctrl+c,因为要是server正常退出后就会销毁共享内存,而ipcrm -m [shmid]这里的shmid也就是688143,删除了在系统中的共享内存。