共享内存是先在物理内存上申请一块空间,多个进程可以将其映射到自己的虚拟地址空间中。 所有进程都可以访问共享内存中的地址,就好像它们是由 malloc 分配的一样。如果某个进程向共享内存写入了数据,所做的改动将立刻被可以访问同一段共享内存的任何其他进程看到。由于它并未提供同步机制,所以我们通常需要用其他的机制来同步对共享内存的访问。
共享内存为多个进程之间共享和传递数据提供了一种有效的方式。
int shmget(key_t key, size_t size, int shmflg);
shmget()用于创建或者获取共享内存
shmget()成功返回共享内存的 ID, 失败返回-1
key: 不同的进程使用相同的 key值可以获取到同一个共享内存,(注意:这里的值和信号量的值一样也没有关系,因为类型不一样;
size:
创建共享内存时,指定要申请的共享内存空间大小
shmflg: IPC_CREAT IPC_EXCL
void* shmat(int shmid, const void *shmaddr, int shmflg);
shmat()将申请的共享内存的物理内存映射到当前进程的虚拟地址空间上
shmat()成功返回返回共享内存的首地址,失败返回 NULL(像malloc一样给共享空间的起始地址),看帮助手册失败返回的是(void *)-1;
shmaddr:一般给 NULL,由系统自动选择映射的虚拟地址空间 shmflg: 一般给 0(给0就代表的可读写),可以给 SHM_RDONLY为只读模式,其他的为读写
int shmdt(const void *shmaddr);
shmdt()断开当前进程的 shmaddr 指向的共享内存映射
shmdt()成功返回 0, 失败返回-1
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
shmctl()控制共享内存
shmctl()成功返回 0,失败返回-1
cmd: IPC_RMID
//main.c用于写入数据
#include
#include
#include
#include
#include
#include
int main()
{
int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
assert(shmid!=-1);
char* s=(char*)shmat(shmid,NULL,0);
if(s==(char*)-1)
{
exit(1);
}
strcpy(s,"Hello");
shmdt(s);
exit(0);
}
//test.c 用于读取数据
#include
#include
#include
#include
#include
#include
int main()
{
int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
assert(shmid!=-1);
char* s=(char*)shmat(shmid,NULL,0);
if(s==(char*)-1)
{
exit(1);
}
printf("%s\n",s);
shmdt(s);
shmctl(shmid,IPC_RMID,NULL);
exit(0);
}
//sem.h
#include
#include
#include
union semun
{
int val;
};
void sem_init();
void sem_p(int index);
void sem_v(int index);
void sem_destroy();
//sem.c
#include"sem.h"
#define SEM_NUM 2
static int semid=-1;
void sem_init()//创建信号量,并初始化
{
semid=semget((key_t)1234,SEM_NUM,IPC_CREAT|IPC_EXCL|0600);
if(semid==-1)
{
semid=semget((key_t)1234,SEM_NUM,0600);
if(semid==-1)
{
perror("semget error\n");
}
}
else
{
int arr[SEM_NUM]={1,0};
for(int i=0;i<SEM_NUM;i++)
{
//初始化
union semun a;
a.val=arr[i];
if(semctl(semid,i,SETVAL,a)==-1)//全新创建成功,就初始化
{
perror("semctl init error");
}
}
}
}
void sem_p(int index)//p操作
{
if(index<0||index>=SEM_NUM)
{
return;
}
struct sembuf buf;
buf.sem_num=index;
buf.sem_op=-1;//p操作
buf.sem_flg=SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("p errro\n");
}
}
void sem_v(int index)
{
if(index<0||index>=SEM_NUM)
{
return ;
}
struct sembuf buf;
buf.sem_num=index;
buf.sem_op=1;//v操作
buf.sem_flg=SEM_UNDO;
if(semop(semid,&buf,1)==-1)
{
perror("v error\n");
}
}
void sem_destroy()
{
if(semctl(semid,0,IPC_RMID)==-1)
{
perror(" destroy sem error\n");
}
}
//a.c
#include
#include
#include
#include
#include
#include
#include"sem.h"
int main()
{
int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
assert(shmid!=-1);
char* s=(char*)shmat(shmid,NULL,0);
if(s==(char*)-1)
{
exit(1);
}
sem_init();
while(1)
{
printf("Input:");
char buff[128]={0};
fgets(buff,128,stdin);
sem_p(0);
strcpy(s,buff);
sem_v(1);
if(strncmp(buff,"end",3)==0)
{
break;
}
}
shmdt(s);
exit(0);
}
//b.c
#include
#include
#include
#include
#include
#include
#include"sem.h"
int main()
{
int shmid=shmget((key_t)1234,256,IPC_CREAT|0600);
assert(shmid!=-1);
char* s=(char*)shmat(shmid,NULL,0);
if(s==(char*)-1)
{
exit(1);
}
sem_init();
while(1)
{
sem_p(1);
if(strncmp(s,"end",3)==0)
{
break;
}
printf("read:%s",s);
sleep(1);
sem_v(0);
}
shmdt(s);
sem_destroy();
shmctl(shmid,IPC_RMID,NULL);
exit(0);
}