共享内存允许一个或多个进程通过同时出现在它们虚拟地址空间中的内存来通讯。共享内存是最有用的进程间通信方式,也是最快的 IPC 形式。 由于多个进程共享同一块内存区域, 必然需要某种同步机制,互斥锁和信号量都可以。
采用共享内存通信的一个显而易见的好处是效率高, 因为进程可以直接读写内存,而不需要任何数据的拷贝。
System V共享内存
头文件
#include <sys/shm.h>
#include <sys/ipc.h>
1、shmget 共享内存的创建
int shmget (key_t key, size_t size, int flag); 成功返回共享存储ID,错误返回-1
shmget是用来创建或者访问一块共享内存的函数,返回值为shmid(共享内存标示符)
参数:key:和信号量一样,程序需要提供一个参数key, 它有效地为共享内存段命名。有一个特殊的键值IPC_PRIVATE, 它用于创建一个只属于创建进程的共享内存, 通常不会用到。size:以字节为单位指定需要共享的内存容量。shmflag:包含9个比特的权限标志, 它们的作用与创建文件时使用的mode标志是一样。由IPC_CREAT定义的一个特殊比特必须和权限标志按位或 才能创建一个新的共享内存段。返回值:创建成功,则返回一个非负整数,即共享内存标识;如果失败,则返回-1。
int shmctl (int shmid, int cmd, struct shmid_ds,*buf);
shmid_ds结构至少包含以下成员:
struct shmid_ds { uid_t shm_perm.uid; uid_t shm_perm.gid; mode_t shm_perm.mode; }
参数:shm_id:是shmget返回的共享内存标识符。command::是要采取的动作,它可以取3个值:
IPC_STAT 获取。把shmid_ds结构中的数据设置为共享内存的当前关联值IPC_SET 设置。如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值IPC_RMID 删除。删除共享内存段
buf :是一个指针,包含共享内存模式和访问权限的结构。返回值:成功时,返回0,失败时,返回-1.
3、shmat 共享内存的链接
void *shmat (int shmid ,const void *addr, int flag); 连接到地址空间
第一次创建共享内存段时,它不能被任何进程访问。要想启动对该内存的访问,必须将其连接到一个进程的地址空间。
参数:
shm_id : 由shmget返回的共享内存标识。
shm_add: 指定共享内存连接到当前进程中的地址位置。它通常是一个空指针,表示让系统来选择共享内存出现的地址。
shmflg : 是一组标志。它的两个可能取值是:
SHM_RND, 和shm_add联合使用,用来控制共享内存连接的地址。
SHM_RDONLY, 它使连接的内存只读
返回值:
如果调用成功, 返回一个指向共享内存第一个字节的指针;
如果失败,返回-1.
4、shmdt 共享内存的分离
int shmdt (void *addr);对共享内存操作结束时,脱离该段
参数:
shm_addr:shmat返回的地址指针。
返回值:
成功时,返回0,
失败时,返回-1。
NOTE:共享内存分离并未删除它,只是使得该共享内存对当前进程不再可用。
实例b程序负责向共享内存中写入数据,a程序负责从内存中读出共享的数据,它们之间并没有添加同步操作。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define BUF_SIZE 1024
#define MYKEY 25
int main()
{
int shmid;
char *shmptr;
if((shmid = shmget(MYKEY,BUF_SIZE,IPC_CREAT)) ==-1)
{
printf("shmget error \n");
exit(1);
}
if((shmptr =shmat(shmid,0,0))==(void *)-1)
{
printf("shmat error!\n");
exit(1);
}
while(1)
{
printf("input:");
scanf("%s",shmptr);
}
exit(0);
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define BUF_SIZE 1024
#define MYKEY 25
int main()
{
int shmid;
char * shmptr;
if((shmid = shmget(MYKEY,BUF_SIZE,IPC_CREAT)) ==-1)
{
printf("shmget error!\n");
exit(1);
}
if((shmptr = shmat(shmid,0,0)) == (void *)-1)
{
printf("shmat error!\n");
exit(1);
}
while(1)
{
printf("string :%s\n",shmptr);
sleep(3);
}
exit(0);
}