之前提到了进程间通信的管道,消息队列,信号量,然后其中信号量是PV操作,操控的是一个共享资源。在我们提到的IPC模块中,消息队列针对的是数据单元的信息传送,管道不属于system V IPC的部分,所以按照一个操作系统的整体来说,他应该也有着一个关于字节流的消息传输,并且要比之前都要快,还要跟我们之前所说的信号量利用起来,所以就出现了共享内存的概念。
什么是共享内存?
共享内存是多个进程之间共享内存区域的一种进程间的通信方式,他是在多个进程之间对内存段进行映射的方式实现内存共享的,这是IPC最快捷的方式,因为共享内存的方式的通信没有中间过程,二管道,消息队列等方式则是需要将数据通过中间机制进行转换。
共享内存方式直接将某段内存段进行映射,多个进程间的共享内存是统一快的物理空间,仅仅阿是地址不同而已,因此不需要进行复制,可以直接使用此段空间。
下面我们就来了解Linux下的共享内存相关的函数:
1.创建共享内存函数:
#include<sys/ipc.h>
#include<sys/shm.h>
int shmget(key_t key,size_t size,int shmflg);
第一个参数是关键字的值,然后,这个值将与内核中现有德1其他共享内存段的关键字值相比较,比较之后,依赖第3个参数,跟前面消息队列的一样。
2.获取共享内存地址函数shmat()
函数shmat()用来获取共享内存的地址,获取共享内存成功后,可以像使用通用内存一样对其进行读写操作,
#include<sys/ipc.h>
#include<sys/shm.h>
void* shmat(int shmid,const void *shmaddr,int shmflg);
int shmdt(const void *shmaddr);
如果shmaddr参数值等于0,则内科将试着查找一个未映射的区域,用户可以指定一个地址,但通常改地址只用于访问所拥有的硬件,或者解决与其他应用程序的冲突。SHM_RND标志可以与标志参数进行OR操作,结果在置为标志参数。SHM_RDONLY标志参数进行OR操作,结果在置为标志参数,这样映射的共享内存端智能标记为只读方式。
shmdt()用于删除一段共享内存,这个函数之中,成功完成了断开连接操作以后,相关的shmid_ds结构的shm_nattch成员的值将减去1。如果这个值减到0.则内核将真正删除这个共享内存。
4.共享内存控制函数shmctl()
#include<sys/ipc.h>
#include<sys/shm.h>
int shmctl(int shmid,int cmd,struct shmid_ds*buf);
第二个参数为:IPC_SET,获取内存短的shmid_ds结构。并把它存储在buf参数所指定的地址中。设置内存段shmid_ds结构的ipc_pern成员的值,此命令是从buf参数中获得该值。
IPC_RMID:标记某内存段,以被删除。并不是真正的把内存段从内存中删除,相反,它只是标记上该内存段,以备将来删除,最后一个断开,删除操作才会发生。
下面看看实际代码:
//shm.h
#pragma once
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define _PATH_ "."
#define _PROJECT_ 0x777
#define _SHM_SIZE_ 4*1024
int get_shm();
void* at_shn();
int delete_shm();
int rm_shm();
//shm.c
#include "shm.h"
int get_shm()
{
key_t key = ftok(_PATH_,_PROJECT_);
if(key < 0)
{
perror("ftok");
return -1;
}
int flag =IPC_EXCL| IPC_CREAT |0666;
int shm_id = shmget(key,_SHM_SIZE_,flag);
if(shm_id < 0)
{
printf("shmid error");
}
else
{
printf("shmid success");
}
return shm_id;
}
void* at_shm(int shm_id)
{
return shmat(shm_id,NULL,0);
}
int delete_shm(char *addr)
{
return shmdt(addr);
}
int rm_shmctl(int shm_id)
{
return shmctl(shm_id,IPC_RMID,NULL);
}
//shm_test.c
#include "shm.h"
int main()
{
int shm_id = get_shm();
if(shm_id < 0)
{
printf("HHH");
}
pid_t id = fork();
if(id <0)
{
printf("fork error\n");
return 1;
}
else if(id == 0)
{
char *buf = (char *)at_shm(shm_id);
printf("child");
int i = 0;
while(i < 4095)
{
buf[i] = 'A';
++i;
buf[i] = '\0';
sleep(1);
}
buf[4095] = '\0';
delete_shm(buf);
}
else
{
int i = 0;
char *buf = (char *)at_shm(shm_id);
printf("father");
while(i<4095)
{
printf("%s\n",buf);
++i;
sleep(1);
}
delete_shm(buf);
waitpid(id,NULL,0);
rm_shmctl(shm_id);
}
return 0;
}
运行结果:
总结:
其实共享内存是在IPC进程间通信最快的一种方式,因为他是直接针对物理地址进行的操作,而且对于他的资源控制,我们需要配合信号量进行操作,来防止死锁的产生。
转载于:https://blog.51cto.com/memory73/1765844