系统v(共享内存)

1.对于系统V共享内存,主要有以下几个API:shmget()、shmat()、shmdt()及shmctl()。

2.shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。

shmat()把共享内存区域映射到调用进程的地址空间 中去,这样,进程就可以方便地对共享区域进行访问操作。

shmdt()调用用来解除进程对共享内存区域的映射。

shmctl实现对共享内存区域的控制操 作。

这里我们不对这些系统调用作具体的介绍,读者可参考相应的手册页面,后面的范例中将给出它们的调用方法。

注:shmget的内部实现包含了许多重要的系统V共享内存机制;shmat在把共享内存区域映射到进程空间时,并不真正改变进程的页 表。当进程第一次访问内存映射区域访问时,会因为没有物理页表的分配而导致一个缺页异常,然后内核再根据相应的存储管理机制为共享内存映射区域分配相应的 页表。

3、系统V共享内存限制

在/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(共享内存)的更多相关文章

  1. system v和posix的共享内存对比 & 共享内存位置

    参考 http://www.startos.com/linux/tips/2011012822078.html 1)Linux和所有的UNIX操作系统都允许通过共享内存在应用程序之间共享存储空间. 2 ...

  2. Linux进程IPC浅析[进程间通信SystemV共享内存]

    Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...

  3. System IPC 与Posix IPC(semaphore信号灯)

    POSIX下IPC主要包括三种: posix message queue posix semaphores posix shared memory sysytem v IPC包括: system v ...

  4. System IPC 与Posix IPC(msg消息对列)

    系统消息队列: 一.消息队列基本概念 系统V消息队列是随内核持续的,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除.因此系统中记录消息队列的数据结构(struct ipc_ids ...

  5. OS: 生产者消费者问题(二) ---- 系统V IPC通信-信号量和共享内存

    在上一篇“OS: 生产者消费者问题(多进程+共享内存+信号量)”中提到的方法二: 如果进程之间并没有父子关系,但是协商好了共享存储的 KEY , 那么在每个进程中,就可以通过 KEY 以及 shmge ...

  6. POSIX systemV共享内存的区别

    POISX共享内存分为两种方式: 1.内存映射文件 特点:共享内存的改变能在文件中体现: 2.共享内存区对象 特点:共享内存的改变在文件上看不出来(实际上根本打不开该文件): 以上两者都是基于mmap ...

  7. POSIX之共享内存

    shm_write.c: #include<stdio.h> #include<stdlib.h> #include <stdlib.h> #include < ...

  8. Linux IPC之共享内存

    System V共享内存机制: shmget  shmat  shmdt  shmctl 原理及实现: system V IPC机制下的共享内存本质是一段特殊的内存区域,进程间需要共享的数据被放在该共 ...

  9. 细说linux IPC(三):mmap系统调用共享内存

    [版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途]         前面讲到socket的进程间通 ...

随机推荐

  1. Unity热更方案汇总

    http://www.manew.com/thread-114496-1-1.html   谈到目前的代码热更方案:没什么特别的要求   <ignore_js_op>    toLua(效 ...

  2. ES6展开运算符(...)

    数组字面量中使用展开运算符 我们可以这样合并数组: var arr1=['a','b','c']; var arr2=[...arr1,'d','e']; //['a','b','c','d','e' ...

  3. Vue父子组件生命周期执行顺序及钩子函数的个人理解

    先附一张官网上的vue实例的生命周期图,每个Vue实例在被创建的时候都需要经过一系列的初始化过程,例如需要设置数据监听,编译模板,将实例挂载到DOM并在数据变化时更新DOM等.同时在这个过程中也会运行 ...

  4. 线上服务器PHP版本编译安装升级全记录

    1.将原来的PHP重命名一下 cd /usr/local/bin/ mv php php.2.9 2.安装依赖 yum install gcc gcc-c++ libxml2 libxml2-deve ...

  5. [转]Entity Framework Sprocs with Multiple Result Sets

    本文转自:https://msdn.microsoft.com/en-us/data/jj691402.aspx Entity Framework Sprocs with Multiple Resul ...

  6. php array 数组及数组索引

    array (PHP 4, PHP 5, PHP 7) array — 新建一个数组 说明 array array ([ mixed $... ] ) 创建一个数组.关于数组是什么的信息请阅读数组一节 ...

  7. spring框架笔记

    Spring实现依赖注入的两种方式: 1.构造方法注入 2.set方法注入,p标签注入 Spring中事务的两种实现方式: 编程式事务管理 声明式事务管理(推荐) Spring增强类型: Before ...

  8. Python-并发编程(进程)

    接下来我们用几天的时间说一说python中并发编程的知识 一.背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作 ...

  9. JavaEE中表现层、持久层、业务层的职责分析(转载)

    表现层.持久层.业务层 注:本文转载于:http://www.blogjava.net/jiabao/archive/2007/04/08/109189.html 为了实现web层(struts)和持 ...

  10. Android setTag()/getTag()

    View中的setTag(Onbect)表示给View添加一个格外的数据,以后可以用getTag()将这个数据取出来. 可以用在多个Button添加一个监听器,每个Button都设置不同的setTag ...