共享内存
进程间共享内存通信,原理很简单,系统开辟一块内存空间,将其映射到物理内存,不同进程可以通过访问这个公共的共享空间完成数据交换,达到进程间通信的目的。访问快,使用简单。不需要额外的函数(如read
write
等)
使用共享内存包含两个步骤:
- 创建共享内存,使用
shmget
函数。- 映射共享内存,将这段创建的共享内存映射到具体的进程空间,使用
shmat
函数。
shmget
函数结构如下:
int shmget(key_t key,int size,int shmflg)
参数说明:
key:
0
(IPC_PRIVATE
):会建立新共享内存对象;- 大于
0
的32
位整数:视参数shmflg
来确定操作。通常要求此值来源于ftok
返回的IPC
键值size:
- 大于
0
的整数:新建的共享内存大小,以字节为单位;0
:只获取共享内存时指定为0shmflag:
0
:取共享内存标识符,若不存在则函数会报错IPC_CREAT
:当shmflg&IPC_CREAT
为真时,如果内核中不存在键值与key
相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符IPC_CREAT|IPC_EXCL
:如果内核中不存在键值 与key
相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错shmflg
是权限标志,它的作用与open
函数的mode
参数一样,如果要想在key
标识的共享内存不存在时,创建它的话,可以与IPC_CREAT
做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644
,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。返回值:
- 如果成功,返回共享内存标识符;
- 如果失败返回
-1
;
shmat()
函数结构如下:
int shmat(int shmid,char *shmaddr,int flag)
参数说明
shmid:
shmget
函数返回的共享存储标识符;shmaddr
- 指定映射内存地址指针(通常写
0
,由系统自动分配共享内存的物理地址,防止自己指定的地址被占用而导致创建失败);flag
- 决定以什么方式来确定映射地址(通常为0);
返回值:
- 如果成功返回共享内存映射到进程中的地址;如果失败,返回-1;
当一个进程不在需要共享内存时,使用shmdt
函数把它从进程地址空间中脱离
shmdt()
函数结构如下:
int shmdt(char *shmaddr)
参数说明:
shmaddr:
- 共享内存的物理地址 由
shmat
函数返回
共享内存控制函数shmctl函数,用于控制共享内存
intshmctl(intshmid, intcmd, structshmid_ds *buf);
参数:
shmid:
- 由
shmget
返回的共享内存标识码cmd:
- 将要采取的动作(有三个可取值)
IPC_STAT
把shmid_ds
结构中的数据设置为共享内存的当前关联值IPC_SET
在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds
数据结构中的值IPC_RMID
删除共享内存段buf:
- 指向一个保存着共享内存的模式状态和访问权限的数据结构
返回值:
- 成功返回
0
;失败返回-1
创建共享内存的代码:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main(int argc, char *argv[])
{
int ret = 0;
int shmid;
//创建共享内存 ,相当于打开文件,文件不存在则创建
shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT | 0666);
if (shmid == -1)
{
perror("shmget err");
return errno;
}
printf("shmid:%d \n", shmid);
Teacher *p = NULL;
//将共享内存段连接到进程地址空间
p = shmat(shmid, NULL, 0);//第二个参数shmaddr为NULL,核心自动选择一个地址
if (p == (void *)-1 )
{
perror("shmget err");
return errno;
}
strcpy(p->name, "aaaa");
p->age = 33;
//将共享内存段与当前进程脱离
shmdt(p);
printf("键入1 删除共享内存,其他不删除\n");
int num;
scanf("%d", &num);
if (num == 1)
{
//用于控制共享内存
ret = shmctl(shmid, IPC_RMID, NULL);//IPC_RMID为删除内存段
if (ret < 0)
{
perror("rmerrr\n");
}
}
return 0;
}
获取共享内存的代码:
#include<stdio.h>
#include<stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<errno.h>
typedef struct _Teacher
{
char name[64];
int age;
}Teacher;
int main(int argc, char *argv[])
{
int ret = 0;
int shmid;
//shmid = shmget(0x2234, sizeof(Teacher), IPC_CREAT |IPC_EXCL | 0666);
//打开获取共享内存
shmid = shmget(0x2234, 0, 0);
if (shmid == -1)
{
perror("shmget err");
return errno;
}
printf("shmid:%d \n", shmid);
Teacher *p = NULL;
//将共享内存段连接到进程地址空间
p = shmat(shmid, NULL, 0);
if (p == (void *)-1 )
{
perror("shmget err");
return errno;
}
printf("name:%s\n", p->name);
printf("age:%d \n", p->age);
//将共享内存段与当前进程脱离
shmdt(p);
printf("键入1 程序暂停,其他退出\n");
int num;
scanf("%d", &num);
if (num == 1)
{
pause();
}
return 0;
}