System IPC 与Posix IPC(共享内存)
系统v(共享内存)
2.shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。
shmat()把共享内存区域映射到调用进程的地址空间 中去,这样,进程就可以方便地对共享区域进行访问操作。
shmdt()调用用来解除进程对共享内存区域的映射。
shmctl实现对共享内存区域的控制操 作。
这里我们不对这些系统调用作具体的介绍,读者可参考相应的手册页面,后面的范例中将给出它们的调用方法。
注:shmget的内部实现包含了许多重要的系统V共享内存机制;shmat在把共享内存区域映射到进程空间时,并不真正改变进程的页 表。当进程第一次访问内存映射区域访问时,会因为没有物理页表的分配而导致一个缺页异常,然后内核再根据相应的存储管理机制为共享内存映射区域分配相应的 页表。
在/proc/sys/kernel/目录下,记录着系统V共享内存的一下限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做。
#include <sys/ipc.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h> #include <string.h>
typedef struct {
char name[];
int age;
}people; int main(int argc,char *argv[]){ int shm_id ,i;
key_t key;
char temp;
people *p_map;
char* name = "./myshm";
key = ftok(name,);
if(key==-){
perror("ftok error!");
}
shm_id = shmget(key,,IPC_CREAT);
if(shm_id ==-){
perror("shmget error");
}
p_map = (people*)shmat(shm_id,NULL,);
temp = 'a';
for(i = ;i<;i++)
{
temp +=;
memcpy((*(p_map +i )).name,&temp, );
(*(p_map + i)).age = +i;
}
if(shmdt(p_map)==-)
perror("detach error");
} #include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h> typedef struct {
char name[4];
int age;
}people;
int main(int argc,char *argv[]){
int shm_id ,i;
key_t key;
char temp;
people *p_map;
char* name = "./myshm";
key = ftok(name,0);
if(key==-1){
perror("ftok error!");
}
shm_id = shmget(key,4096,IPC_CREAT);
if(shm_id ==-1){
perror("shmget error");
}
p_map = (people*) shmat(shm_id,NULL,0);
for(i = 0;i<10;i++){
printf("Name: %s,Age: %d\n",(*(p_map+i)).name,(*(p_map+i)).age);
}
if(shmdt(p_map)==-1)
{
perror("detach error");
}
}
注意:
1、 系统V共享内存中的数据,从来不写入到实际磁盘文件中去;而通过mmap()映射普通文件实现的共享内存通信可以指定何时将数据写入磁盘文件中。 注:前面讲到,系统V共享内存机制实际是通过映射特殊文件系统shm中的文件实现的,文件系统shm的安装点在交换分区上,系统重新引导后,所有的内容都丢失。
2、 系统V共享内存是随内核持续的,即使所有访问共享内存的进程都已经正常终止,共享内存区仍然存在(除非显式删除共享内存),在内核重新引导之前,对该共享内存区域的任何改写操作都将一直保留。
3、 通过调用mmap()映射普通文件进行进程间通信时,一定要注意考虑进程何时终止对通信的影响。而通过系统V共享内存实现通信的进程则不然。 注:这里没有给出shmctl的使用范例,原理与消息队列大同小异。
共享内存允许两个或多个进程共享一给定的存储区,因为数据不需要来回复制,所以是最快的一种进程间通信机制。共享内存可以通过 mmap()映射普通文件(特殊情况下还可以采用匿名映射)机制实现,也可以通过系统V共享内存机制实现。应用接口和原理很简单,内部机制复杂。为了实现 更安全通信,往往还与信号灯等同步机制共同使用。
共享内存涉及到了存储管理以及文件系统等方面的知识,深入理解其内部机制有一定的难度,关键还要紧紧抓住内核使用的重要数据结构。系统 V共享内存是以文件的形式组织在特殊文件系统shm中的。通过shmget可以创建或获得共享内存的标识符。取得共享内存标识符后,要通过shmat将这 个内存区映射到本进程的虚拟地址空间。
POSIX mmap函数的应用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h> int main( int argc, char ** argv )
{
const uint32_t SHM_SIZE = ;
int fd;
char* ptr = NULL;
if( argc != )
{
printf("Enter your file name!\n");
exit( EXIT_FAILURE );
}
if( ( fd = open( argv[], O_RDWR|O_CREAT, ) ) < )
{
perror( argv[] );
exit(EXIT_FAILURE);
}
// 修改文件长度为共享内存长度,若要同步文件此处很重要,文件大小,决定了文件中能存多少的东西
ftruncate(fd, SHM_SIZE);
/// 以写方式映射
if( ( ptr = (char*)mmap( , SHM_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, ) ) == MAP_FAILED )
{
perror("mmap");
exit( EXIT_FAILURE );
}
memset(ptr,'a', SHM_SIZE/);
/// 加个时间点检查,比较MS_ASYNC和MS_SYNC的时间差异
//time_t now;
//time_t end;
struct timeval now;
struct timeval end; gettimeofday(&now,NULL);
// msync异步模式也很有意思,测试发现,执行该函数后,即使马上让程序coredown, 数据也可以成功写出而不会丢失
// 写200M的数据,异步模式只用了4us, 如果采用同步模式,则时间是原来的千倍万倍!
msync(ptr, SHM_SIZE/, MS_ASYNC);
msync(ptr, SHM_SIZE/, MS_SYNC);
//time(&end);
gettimeofday(&end,NULL); double second =end.tv_sec - now.tv_sec;
std::cout<<"second"<<second<<std::endl;
double usecond= end.tv_usec - now.tv_usec;
std::cout<<"usecond"<<usecond<<std::endl; #if 1
char buf[]= {};
double tt = second+(usecond/);
sprintf(buf,"%f",tt);
std::cout << "sync td:" <<buf<<"(s)"<< std::endl; #endif
munmap(ptr, SHM_SIZE);
///修正文件大小,改为实际内容的长度
ftruncate(fd, SHM_SIZE/);
close(fd);
return ;
}
C-S模式
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h> typedef struct {
char name[];
int age;
}people; int main(int argc,char *argv[]){ int fd,i;
people *p_map; fd = open(argv[],O_CREAT|O_RDWR,);
p_map = (people *)mmap(NULL,sizeof(people)*,PROT_READ|PROT_WRITE,
MAP_SHARED,fd, );
for(i = ;i<;i++)
{
printf( "name:%s age %d:\n",(*(p_map+i)).name, (*(p_map+i)).age );
}
munmap( p_map,sizeof(people)* ); return ;
}
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h> typedef struct{
char name;
int age;
}people; int main(int argc,char *argv[]){
int fd,i;
people *p_map;
char temp;
fd = open(argv[],O_CREAT|O_RDWR,); lseek(fd,,SEEK_SET);
write(fd,"",sizeof(people)*);
p_map = (people *)mmap(NULL,sizeof(people)*,PROT_READ|PROT_WRITE,MAP_SHARED,fd,); //close(fd);
#if 0
temp = 'a';
for(i = ;i<;i++)
{
temp += ;
memcpy((*(p_map+i)).name,&temp,);
(*(p_map+i)).age = +i;
}
#endif
#if 0
memset(p_map,'b',sizeof(people)*);
msync(p_map,sizeof(people)*,MS_SYNC);
#endif
printf("initializer over \n");
if(-==munmap(p_map,sizeof(people)*)){
perror("munmap error\n");
}
//msync(p_map,sizeof(people)*10,MS_SYNC);
//msync(p_map,sizeof(people)*10,MS_INVALIDATE);
printf("unmap ok \n");
close(fd);
return ;
}
功能:用来创建或打开一个共享内存对象
原型 int shm_open(const char *name, int oflag, mode_t mode);
参数
name:共享内存对象的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255)
oflag:与open函数类似,可以是O_RDONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_TRUNC等。
mode:此参数总是需要设置,如果oflag没有指定了O_CREAT,可以指定为0
返回值:成功返回非负整数文件描述符;失败返回-1
注意,不存在所谓的shm_close 函数,可以直接使用close 来关闭文件描述符。
功能:修改共享内存对象大小,shm_open不像shmget一样可以设置共享内存的大小,但可以使用ftruncate 设置大小。
原型 int ftruncate(int fd, off_t length);
参数
fd: 文件描述符
length:长度
返回值:成功返回0;失败返回-1
功能:获取共享内存对象信息
原型
int fstat(int fd, struct stat *buf);
参数
fd: 文件描述符
buf:返回共享内存状态
返回值:成功返回0;失败返回-1
struct stat 可以参考这里。
类似 shm_ctl(,IPC_STAT,);
功能:删除一个共享内存对象
原型 int shm_unlink(const char *name);
参数
name: 共享内存对象的名字
返回值:成功返回0;失败返回-1
shm_unlink 类似 shm_ctl(,IPC_RMID,);
功能:将共享内存对象映射到进程地址空间。
原型 void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
参数
addr: 要映射的起始地址,通常指定为NULL,让内核自动选择
len:映射到进程地址空间的字节数
prot:映射区保护方式
flags:标志
fd:文件描述符
offset:从文件头开始的偏移量
返回值:成功返回映射到的内存区的起始地址;失败返回-1
在前面曾经介绍了mmap 函数 将文件映射到进程地址空间的作用,其实它还可以将共享内存对象映射到进程地址空间,类似shmat的作用,只是传入的文件描述符fd 是shm_open 返回的。同样地,解除映射可以用munmap,类似shmdt 的作用。
编译时候加上 -lrt 选项,即连接librt 库 (实时库)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h> #define ERR_EXIT(m) \
do { \
perror(x); \
exit(EXIT_FAILURE);\
}while() #define SHM_SIZE 256 int main(){ int fd ;
char path[] = {};
memcpy(path,"./tmp",);
int flag = O_RDWR|O_CREAT;
fd = shm_open(path,flag,); ftruncate(fd,SHM_SIZE); void *m_map ;
m_map = mmap(NULL,SHM_SIZE+,PROT_READ|PROT_WRITE,MAP_SHARED,fd,); memset(m_map,'a',SHM_SIZE); struct stat buf;
fstat(fd,&buf); printf("file size is %d\n",buf.st_size); close(fd);
return ;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h> #define ERR_EXIT(m) \
do { \
perror(x); \
exit(EXIT_FAILURE);\
}while(0) #define SHM_SIZE 256 int main(){ int fd ;
char path[10] = {0};
memcpy(path,"./tmp",10);
int flag = O_RDWR|O_CREAT;
fd = shm_open(path,flag,00777); ftruncate(fd,SHM_SIZE); void *m_map ;
m_map = mmap(NULL,SHM_SIZE+1,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); printf("%s \n",m_map);
close(fd); return 0;
}
System IPC 与Posix IPC(共享内存)的更多相关文章
- system v和posix的共享内存对比 & 共享内存位置
参考 http://www.startos.com/linux/tips/2011012822078.html 1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间. 2 ...
- Linux进程IPC浅析[进程间通信SystemV共享内存]
Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...
- System IPC 与Posix IPC(semaphore信号灯)
POSIX下IPC主要包括三种: posix message queue posix semaphores posix shared memory sysytem v IPC包括: system v ...
- System IPC 与Posix IPC(msg消息对列)
系统消息队列: 一.消息队列基本概念 系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除.因此系统中记录消息队列的数据结构(struct ipc_ids ...
- OS: 生产者消费者问题(二) ---- 系统V IPC通信-信号量和共享内存
在上一篇“OS: 生产者消费者问题(多进程+共享内存+信号量)”中提到的方法二: 如果进程之间并没有父子关系,但是协商好了共享存储的 KEY , 那么在每个进程中,就可以通过 KEY 以及 shmge ...
- POSIX systemV共享内存的区别
POISX共享内存分为两种方式: 1.内存映射文件 特点:共享内存的改变能在文件中体现: 2.共享内存区对象 特点:共享内存的改变在文件上看不出来(实际上根本打不开该文件): 以上两者都是基于mmap ...
- POSIX之共享内存
shm_write.c: #include<stdio.h> #include<stdlib.h> #include <stdlib.h> #include < ...
- Linux IPC之共享内存
System V共享内存机制: shmget shmat shmdt shmctl 原理及实现: system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共 ...
- 细说linux IPC(三):mmap系统调用共享内存
[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 前面讲到socket的进程间通 ...
随机推荐
- 批量修改dos文件到unix
1. 安装dos2unix 2. 执行:find ./ -type f | xargs dos2unix
- FocusBI: 总线矩阵(原创)
关注微信公众号:FocusBI 查看更多文章:加QQ群:808774277 获取学习资料和一起探讨问题. <商业智能教程>pdf下载地址 链接:https://pan.baidu.com/ ...
- 推荐几款基于Bootstrap的响应式后台管理模板
1.Admin LTE 该模版开源免费. AdminLTE - 是一个完全响应式管理模板.基于Bootstrap3的框架.高度可定制的,易于使用.支持很多的屏幕分辨率适合从小型移动设备到大型台式机. ...
- 在 Azure WebApps 中运行64位 Asp.net Core 应用
作为微软下一代的开源的跨平台的开发框架, Asp.net core 正在吸引越来越多的开发者基于其构建现代 web 应用. 目前, Azure App Service 也实现了对 asp.net co ...
- 宏定义中的反斜杠"\"和宏定义的细节说明
转载自:http://www.wtoutiao.com/p/K6csca.html 在阅读C语言代码经常可以看到代码中出现反斜杠"\",不是很明白它的意思,遂对反斜杠"\ ...
- Ubuntu 16.04 开启BBR加速
BBR(Bottleneck Bandwidth and RTT)是Google推出的一个提高网络利用率的算法,可以对网络进行加速,用来干什么大家心里都有B数 Ubuntu开启BBR的前提是内核版本必 ...
- 封装hiredis——C++与redis对接(一)(string的SET与GET操作)
在菜鸟教程自学了redis,总想着像Mysql一样,在C/C++中进行对接.于是查询了一些资料,最后找到了hiredis.然而直接用它的话,难免有点不方便.于是,对其进行封装. hiredis直接去g ...
- 小白学flask之hello,world
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "He ...
- csharp:Google TTS API text to speech
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- BBS登录与注册功能
登录功能 视图函数 def my_login(request): if request.method == 'GET': return render(request, 'login.html') el ...