一、共享内存
两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。
ipcs -m (查看共享内存)
ipcrm -m shmid (删除共享内存)
共享内存的特点:
(1)共享内存就是允许两个不想关的进程访问同一个内存
(2)共享内存是两个正在运行的进程之间共享和传递数据的最有效的方式
(3)不同进程之间共享的内存通常安排为同一段物理内存
(4)共享内存不提供任何互斥和同步机制,一般用信号量对临界资源进行保护。
(5)接口简单
共享内存的缺点:
共享内存没有提供同步的机制,这使得我们在使用共享内存进行进程间通信时,往往要借助其他的手段来进行进程间的同步工作。
二、函数
shmget
shmat
shmdt
shmctl
#include <sys/shm.h>
// 创建或获取一个共享内存:成功返回共享内存ID,失败返回-1
int shmget(key_t key, size_t size, int flag);
// 连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1
void *shmat(int shm_id, const void *addr, int flag);
// 断开与共享内存的连接:成功返回0,失败返回-1
int shmdt(void *addr);
// 控制共享内存的相关信息:成功返回0,失败返回-1
int shmctl(int shm_id, int cmd, struct shmid_ds *buf);
- shmget 创建共享内存
当用shmget函数创建一段共享内存时,必须指定其 size,size的大小应为1024整数倍(4k对齐);而如果引用一个已存在的共享内存,则将 size 指定为0 。 - shmat 将共享内存映射到自己的内存空间
当一段共享内存被创建以后,它并不能被任何进程访问。必须使用shmat函数连接该共享内存到当前进程的地址空间,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问。
第一个参数,shm_id是由shmget函数返回的共享内存标识。
第二个参数,shm_addr指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
第三个参数,shm_flg是一组标志位,通常为0。
返回值:调用成功则返回映射地址的第一个字节,失败返回-1。 - shmdt 解除映射
shmdt函数是用来断开shmat建立的连接的,参数为要解除的地址空间。注意,这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已。
参数shmaddr是shmat函数返回的地址指针
第一个参数,shm_id是shmget函数返回的共享内存标识符。 - shmctl 控制共享内存
shmctl函数可以对共享内存执行多种操作,根据参数 cmd 执行相应的操作。
第一个参数,shm_id是shmget函数返回的共享内存标识符。
第二个参数,command是要采取的操作,它可以取下面的三个值 :
IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
IPC_RMID:删除共享内存段
常用的是IPC_RMID(从系统中删除该共享内存)。
第三个参数,buf是一个结构指针,它指向共享内存模式和访问权限的结构。
三、demo
A写信息到共享内存,B读取
share_A.c
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int shmid;
char *shmaddr;
key_t key;
key = ftok("./share",1);
printf("the key is:%x\n",key);
//创建共享内存 指定size大小1024整数倍
shmid = shmget(key,1024*4,IPC_CREAT|0666);
if(shmid == -1)
{
printf("shmget failed\n");
exit(-1);
}
shmaddr = shmat(shmid,0,0);
//第二个参数和第三个参数指定要映射得物理内存地址
//通常设为是 NULL 0 ,表示要映射得物理内存地址是进程空间得首地址
printf("shmat ok\n");
strcpy(shmaddr,"hello world"); //strcpy将字符串复制到共享内存
sleep(5); //延时5秒等待B从共享内存获取信息
shmdt(shmaddr); // 解除映射
//删除共享内存段
shmctl(shmid,IPC_RMID,0);
printf("quit\n");
return 0;
}
share_B.c
#include<sys/shm.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int shmid;
char *shmaddr;
key_t key;
key = ftok("./share",1);
printf("the key is:%x\n",key);
//获取共享内存,已经创建过,size为0.不过不写0也没有出错
shmid = shmget(key,0,0);
if(shmid == -1)
{
printf("shmget failed\n");
exit(-1);
}
shmaddr = shmat(shmid,0,0);//映射
printf("shmat ok\n");
printf("data:%s\n",shmaddr);//从共享内存读取到A写入的信息
shmdt(shmaddr);
printf("quit\n");
return 0;
}
demo :运行A进程后,要在A设定的sleep(5)5秒延时内,运行B。否则会读取错误,因为A在经5秒延时后就将共享内存删除了。