系统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. Bash编程(2) 循环与分支

    Shell中有三种类型的循环:for, until, while,具有3种类型的条件语句:if, case, 条件操作符(&&, ||). 1. 结束码 命令的结束码可以在命令运行完后 ...

  2. [跨域]跨域解决方法之Ngnix反向代理

    跨域原理:http://www.cnblogs.com/Alear/p/8758331.html 介绍Ngnix之前,我么先来介绍下代理是什么~ 代理相当于中间人,中介的概念 代理分为正向代理和反向代 ...

  3. step5: 编写spider爬取

    改写parse函数 实现功能: 1.获取文章列表页中的文章url并交给scrapy下载后,交给解析函数进行具体字段的解析2.获取下一页的url并交给scrapy进行下载,下载完成后交给parse 提取 ...

  4. NOPI 导出 Excel 2007

    代码: public static void ThisTo<T>( List<T> source, string[] colums, Func<T, object[]&g ...

  5. gradle 构建的 Spring Boot 使用 logback

           文章讲的是配置和使用,入门请看文档先. what 目的: 可以实现log不同级别的日志记录,例如info 在一个文件夹内,另一个级别的在另一个文件夹内. how 配置依赖项 //log ...

  6. Jvm性能监控和常用工具

    JDK常用命令行工具   Jps : jps [options] [hostid]  , -q 只显示jvmid, -m 传递给主类main的参数,-l 类全名,-v jvm启动参数 jstat : ...

  7. Hibernate 注解(Annotations 一)

    1. @Entity 将一个类声明为一个实体bean(即一个持久化POJO类). 2. @Table 声明了该实体bean映射指定的表(table),目录(catalog)和schema名字 3. @ ...

  8. JavaScript中按键事件的e.keyCode || e.which || e.charCode

    1.浏览器的按键事件 浏览器有3种按键事件——keydown,keypress和keyup,分别对应onkeydown.onkeypress和onkeyup3个事件句柄. 一个典型的按键会产生所有这三 ...

  9. JavaScript常用类

    JS常用类 一.Number 1.常用数字 整数:10 小数:3.14 科学计数法:1e5 | 1e-5 正负无穷:Infinity | -Infinity 2.常用进制 二进制:0b1010 八进制 ...

  10. easy html+css tree 简单的HTML+css导航树

    code: show: