系统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. 【随笔】nginx下的301跳转,两个域名指向同一个服务器ip

    301跳转 页面永久性移走,通常叫做301跳转,也叫301重定向,301转向. 指的是当用户点击一个网址时,通过技术手段,跳转到指定的一个网站. 用以解决两个域名指向同一个服务器ip,当访问m.xxx ...

  2. Linux下实现MySQL数据库自动备份

    1.给mysql创建用户备份的角色,并且授予角色SELECT, RELOAD, SHOW DATABASES, LOCK TABLES等权限. mysql> create user 'backu ...

  3. Android规划周期任务

    问题:应用总要周期性的执行某项任务,例如检查服务器上的更新或者提醒用户做某些事情. 解决方案:用AlarmManager来管理和执行任务.AlarmManager可用于计划未来的单次或重复操作,甚至在 ...

  4. Log4j 2.0读取配置文件的方法

    log4j中配置日志文件存放的位置不一定在src下面,即根目录下.这个时候我们需要解决如何加载配置文件的问题.在log4j1.x中解决的方法就比较多了.如:PropertyConfigurator.c ...

  5. WPF的ProgressBar进度条

    1. ProgressBar常用属性 1.1.  Minimum:进度条的最小值,一般为 0 1.2. Maximum:进度条的最大值,一般为100 或者是 某一个数, 如复制文件时,总文件数等 1. ...

  6. 关于Map集合的遍历总结

    Map集合的遍历经常遇到,今天在这里总结一下Map集合遍历的几种方式: public static void main(String[] args){ Map<String,String> ...

  7. Splunk数据处理

    0.提要 本篇主要从技术层面针对Splunk Enterprise中关于数据处理的概念.过程与部件进行了概要性总结. 1.数据管理基本概念 索引(index):Splunk用于存储事件的数据仓库: 索 ...

  8. C#中去除字符串里的多个空格且保留一个空格

    static void Main(string[] args) { // 首先定义一个名为str 的字符串 string str="2         3  4     保留一个空格  ss ...

  9. sql server分页查询

    1.引言 在列表查询时由于数据量非常多,一次性查出来会非常慢,就算一次查出来了,也不能一次性显示给客户端,所以要把数据进行分批查询出来,每页显示一定量的数据,这就是数据要分页. 2.常用的数据分页方法 ...

  10. 数据上下文中的AddOrUpdate方法

    AddOrUpdate是扩展方法,需要添加引用  using System.Data.Entity.Migrations;