共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。
原理:
在Linux下,创建进程A和进程B时,它们都会创建task_struct,虚拟地址空间,页表,通过页表把虚拟空间的共享数据区域的内容映射到物理内存上的同一块空间,这块空间就叫做共享内存。
查看共享内存
ipcs -m
key:唯一键值
shmid:共享内存的标识符
owner:主人
perms:权限,可在shmget的第三个参数后加上
bytes:大小,即shmget的第二个参数size
nattch:挂接数,连接在共享内存上的进程个数
status:状态
删除共享内存
ipcrm -m shmid
shmid是共享内存的编识符
效率
共享内存是进程间通信(IPC)最快的方式,没有之一。因为进程可以直接从内核读取或者写入数据,避免了在进程中再复制数据的过程。
shmget,shmctl,shmat,shmdt函数
1.shmget 创建一个共享内存或得到一个共享内存的标识符
头文件
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型
int shmget(key_t key, size_t size, int shmflg);
- key:由ftok函数获得
key_t ftok(const char *pathname, int proj_id);
pathname:已存在的路径名
proj_id:整数
返回值:经过这个函数运算成功生成一个独一无二的key值,失败返回-1
-
size:要开辟的共享内存的大小
-
shmflg:共享内存的标识符
PIC_CREAT:在内存中找与key相等的共享内存,如果找不到则新建一个共享内存;如果存在则返回此共享内存的标识符
PIC_CREAT|PIC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建,如果存在则报错,即这样创建的共享内存一定是新建的。 -
返回值:成功创建返回共享内存的标识符,失败返回-1
2.shmat 把共享内存区对象映射到调用进程的地址空间
头文件
#include <sys/types.h>
#include <sys/shm.h>
函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg);
- shmid:共享内存的标识符
- shmaddr:指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
- shmflg:SHM_RDONLY:为只读模式,其他为读写模式,默认为0即可
- 返回值:成功返回映射到虚拟地址空间的地址,失败返回-1
3.shmdt 断开共享内存连接
头文件
#include <sys/types.h>
#include <sys/shm.h>
函数原型
int shmdt(const void *shmaddr);
- shmaddr:连接的共享内存的起始地址,即shmat返回的指针
- 返回值:断开成功返回0.失败返回-1
4.shmctl 共享内存管理
头文件
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型
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设为NULL -
buf:共享内存管理结构体。可设NULL
-
返回值:成功返回0,失败返回-1
使用共享内存函数进行通信
client.c文件(用户)
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
int main()
{
key_t k = ftok("/usr/bin/ls",0);
if(k<0)
{
perror("ftok");
return 1;
}
int shmid = shmget(k,4096,IPC_CREAT|0664);
if(shmid<0)
{
perror("shmget");
return 2;
}
char*str =(char*)shmat(shmid,NULL,0);
int i = 0;
while(i<26)
{
str[i] = 'A'+i;
i++;
str[i] = '\0';
sleep(1);
}
shmdt(str);
return 0;
}
server.c文件(服务器)
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
int main()
{
key_t k = ftok("/usr/bin/ls",0);
if(k<0)
{
perror("ftok");
return 1;
}
int shmid = shmget(k,4096,IPC_CREAT);
if(shmid<0)
{
perror("shmget");
return 2;
}
char*str = (char*)shmat(shmid,NULL,0);
int i =0;
while(i<26)
{
printf("client->server:%s\n",str);
i++;
sleep(1);
}
shmdt(str);
if(shmctl(shmid,IPC_RMID,NULL)<0)
{
perror("shmctl");
return 4;
}
return 0;
}
Makefile文件
.PHONY:all
all:client server
client:client.c
gcc -o $@ $^
server:server.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f client server
最终效果
扩展阅读:
共享内存函数(shmget、shmat、shmdt、shmctl)及其范例
进程间通信——共享内存(Shared Memory)