1.共享内存
1.1含义
两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新。
1.2工作流程
用户空间到内存—写;内存到用户空间—读。
1.3特性
(1)数据传输效率快,适用于对数据的速率、数量要求较高的场合(如果要求不高,一般使用消息队列).
(2)共享内存具有内存的通用特性,对共享内存执行写操作时以覆盖的方式写入,对共享内存读取数据后,内存中的数据保留,不会删除。
(3)内核中的内存是不具有共享机制的,在使用共享内存前需要先创建一块共享内存(物理内存)。
(4)共享内存并未提供同步机制,在一个进程结束对共享内存的写操作之前,不可以使用另外一个进程开始对它进行读取。
2.共享内存相关函数
2.1 shmget(创建或打开共享内存)
函数头文件:#include <sys/ipc.h> #include <sys/shm.h> 函数原型: intshmget(key_t key, size_t size, int shmflg); 函数功能:在内存上创建一块共享内存空间; 函数参数: key_t key:键值 父子进程亲缘进程之间键值可以是0x000000私有IPC_PRIVATE(#defineIPC_PRIVATE ((__kernel_key_t) 0) ) size_t size:大小创建共享内存空间大小; int shmflg:标志(如:IPC_CREAT |操作权限) IPC_CREAT:创建 IPC_EXCL与IPC_CREAT:如果已存在共享内存返回错误,如果未存在则创建共享内存; 系统调用: SYSCALL_DEFINE3(shmget,key_t, key, size_t, size, int, shmflg) -> ipcget 返回值:成功返回共享内存编号,失败返回-1; 备注:如果在父子进程之间(具有亲缘关系的进程间的使用)使用共享内存,Key键值可以为“0”或“IPC_PRIVATE”。两个任意进程之间使用共享内存,Key键值可以直接填写一个非0的整数或通过ftok 让系统分配一个Key键值。并且共享内存不同于有名管道,有名管道的同一根管道只能被创建一次,而共享内存则可以创建多次(几个进程使用共享内存,就需要分别在几个进程中创建,并且保证通信的进程使用的KEY值一致)。而在父子进程中,只需在创建进程之前创建一次共享内存即可。 |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(int argc,char *argv[])
{
int shmid = shmget(0x88888,512,IPC_CREAT|0644);
if(shmid == -1)
{
perror("shmget");
exit(1);
}
printf("共享内存ID:%d\n",shmid);
return 0;
}
2.2 shmat(映射共享内存)
映射:将共享内存映射到进程中的内存空间;
为了方便用户空间对内存的操作,使用地址映射的方式;
函数shmat用于将共享内存段映射到进程空间的某一地址;
意义:反应速度快,操作方便。
函数头文件:#include <sys/types.h> #include <sys/shm.h> 函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg); 函数功能:把共享映射到进程空间(建立共享内存与当前的进程的映射关系)。 函数参数: int shmid:共享内存的ID号,能够确定计算机中唯一的共享内存块; const void *shmaddr:如果此参数为NULL系统会自动分配未使用的地址;(常用) int shmflg:标志 SHM_RDONLY只读 可读可写为0 返回值:void *:成功时映射后的首地址,失败时返回-1。 |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(int argc,char *argv[])
{
int shmid = shmget(0x88888,512,IPC_CREAT|0644);
if(shmid == -1)
{
perror("shmget");
exit(1);
}
printf("共享内存ID:%d\n",shmid);
//进行映射
int * p = shmat(shmid,NULL,0);
//进行映射
int * q = shmat(shmid,NULL,0);
//读写操作
*p =10;
printf("%d\n",*q);
//字符串
char * p1 = shmat(shmid,NULL,0);
char * q1 = shmat(shmid,NULL,0);
//写
strcpy(p1,"hello");
//读
printf("%s\n",q1);
return 0;
}
2.3 解除映射
函数头文件:#include <sys/types.h> #include <sys/shm.h> 函数原型:int shmdt(const void *shmaddr); 函数功能:撤销当前的进程与共享内存之间的映射关系。 函数形参: const void *shmaddr:进程空间映射后到地址(shmat函数的返回值)。 函数返回值:int:成功返回0,失败返回-1。 |
2.4 删除共享内存
函数头文件:#include <sys/ipc.h> #include <sys/shm.h> 函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf); 函数功能:控制共享内存具体操作。 函数形参: int shmid:共享内存的id(shmget函数的返回值)。 int cmd:共享内存控制命令。 IPC_STAT:查看共享内存的特性。 IPC_SET:设置共享内存的特性。 IPC_RMID:删除共享内存。 struct shmid_ds *buf:共享内存特性结构体(命令附带参数),不需要则指定为NULL。 函数返回值:int:成功返回0,失败返回-1。 备注:如果需要删除共享内存,必须保证共享内存的所有连接全部断开(取消映射)后才能被真正删除。 映射共享内存 |
2.5 应用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(int argc,char *argv[])
{
int shmid = shmget(0x088888,512,IPC_CREAT|0644);
if(shmid == -1)
{
perror("shmget");
exit(1);
}
printf("共享内存ID:%d\n",shmid);
if(strcmp(argv[1],"w")==0)
{
//字符串
char * p1 = shmat(shmid,NULL,0);
for(int i = 0; ;i++)
{
//写
char buff[512]={0};
sprintf(buff,"%04d",i);
strcpy(p1,buff);
sleep(1);
}
shmdt(p1);
}
else if(strcmp(argv[1],"r")==0)
{
char * q1 = shmat(shmid,NULL,0);
while(1)
{
printf("%s\n",q1);
}
shmdt(q1);
}
shmctl(shmid,IPC_RMID, NULL);
return 0;
}