共享内存是进程间通信中最简单的方式之一。共享内存在各种进程间通信方式中具有最高的效率。因为系统内核没有对访问共享内存进行同步,您必须提供自己的同步措施。解决这些问题的常用方法是通过使用信号量进行同步。
1.函数shmget
我们使用函数shmget来获得一个共享内存标识符
#include<key_t key,size_t size,int flag>
返回值:成功返回ID,出错返回-1
参数key_t:不同进程之间是通过这个数值来联系的。
参数size:表示该共享存储段的长度,创建一个新段必须指定size的值,如果引用一个先存的段,该值为0;
参数flag:表示权限
2.函数shmctl
使用函数shmctl来执行多种操作
#include<sys.shm.h>
int shmget(int shmid,int cmd,shtruct shmid_ds *buf);
返回值:成功返回0,出错返回-1
参数cmd指定几个命令,包括IPC_RMID删除等
3.函数shmat
一旦创建了一个共享存储段,进程就调用shmat将其连接到它的地址空间去。
#include<sys/shm.h>
int *shmat(int shmid,const void *addr,int flag);
返回值:成功返回指向共享存储段的指针;若出错,返回-1
共享存储段连接到进程的哪个地址上与addr参数,以及flag中是否指定SHM_RND有关。
1)若addr为0,则此段连接到由内核选择的第一个可用地址上,这是推荐使用的方式
2)若addr非0,并且没有指定SHM_RND,则此段连接到addr所指定的地址上
参数flag:若指定了SHM_RDONLY,则以只读方式打开,否则以读写方式打开。
4.函数shmdt
当共享内存的操作结束时,则调用shmdt来与该段分离,但并不是删除
#include<sys/shm.h>
int shmdt(const void *addr);
返回值:成功返回0,失败返回-1
参数address,是函数shmat的返回值。
例程往共享内存写数据
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shmdata.h"
struct shared_use_st
{
int written; //标志读写
char text[512]; //缓存数据
};
int main()
{
int running=1;
char buffer[512];
int shmid;
void *shm=NULL;
struct shared_use_st *shared = NULL;
shmid=shmget((key_t)1234,sizeof(struct shared_use_st),0666|IPC_CREAT); //创建一个共享内存
if(shmid==-1)
{
fprintf(stderr,"shmget failed\n");
exit(1);
}
shm=shmat(shmid,0,0); //连接到当前进程的地址
if(shm==(void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(1);
}
shared=(struct shared_use_st *)shm;
while(running)
{
if(shared->written!=0) //当前不可写
{
sleep(1);
}
fgets(buffer,512,stdin); //写入数据
strncpy(shared->text,buffer,512);
shared->written=1;
if(strncmp(buffer,"end",3)==0)
running=0;
}
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
sleep(2);
exit(0);
}
读取共享内存的例程
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
struct shared_use_st{
int written; //作为一个读或写的标志。 0表示可写,非0表示可读
char text[2048]; //数据缓存在这里
}
int main()
{
int shmid;
int running=1;
void *shm = NULL;//分配的共享内存的原始首地址
struct shared_use_st *shared;//指向shm
shmid=shmget(key_t(1234),sizeof(struct shared_use_st),0666|IPC_CREAT); //创建一个共享存储段
if(shmid<0)
{
fprintf(stderr,"shmid failed\n");
exit(1);
}
shm=shmat(shmid,0,0); //将共享内存链接到当前的进程的地址空间
if(shm==(void *)-1)
{
fprintf(stderr,"shmat failed\n");
exit(1);
}
shared=(struct shared_use_st * )shm;
shared->written=0;
while(runing)
{
if(shared->written!=0) //当前无进程写,可读
{
printf("%s",shared->text);
sleep(3);
shared->written=0; //读取完后设置为可写
if(strncmp(shared->text, "end", 3) == 0)
running = 0;
}
else
sleep(1);
}
if(shmdt(shm) == -1) //从当前进程分离
{
fprintf(stderr, "shmdt failed\n");
exit(1);
}
if(shmctl(shmid, IPC_RMID, 0) == -1) //删除
{
fprintf(stderr, "shmctl(IPC_RMID) failed\n");
exit(1);
}
exit(0);
}