zoukankan      html  css  js  c++  java
  • Linux进程间通信---共享内存

    • 共享内存允许多个进程共享一个给定的内存空间,进程可以直接读写内存,因此是IPC中速度最快的。
    • Linux中,内核专门留出了一块内存区作为共享内存区,用于多个进程交换信息。需要通信的进程将共享内存区映射到自己的私有地址空间,从而使读写进程地址空间就相当于读写内存区。使用共享内存的头文件是#include <sys/shm.h>
    • 由于多个进程读写同一块内存区,所以需要进行同步处理,一般要和信号量联合使用(也可使用互斥量和记录锁)。
    • 共享内存段默认是32M字节。
    • 共享内存的操作流程(只使用于相关进程,即亲缘进程间的通信):
      • 创建/打开一块共享内存区
      • 把指定的共享内存映射到进程的地址空间
      • 撤销共享内存映射
      • 删除共享内存对象(key代表的IPC对象)
    • 共享内存常用函数:
      • shmget(key, size, flag):创建新的共享内存段或者取得已有的共享内存段,函数返回共享存储段的ID(shmid)。key标识共享内存的键值,两个进程用相同的key时用shmget得到的shmid是相同的,此时可以访问同一块共享内存。size表示获得的共享内存大小。flag表示共享内存块的访问权限,如果想共享内存段不存在时新建一个,用IPC_CREAT与权限值做位与操作即可。
      • shmat(shmid, addr, flag):将共享存储段映射到进程的地址空间。应当制定addr为0,由系统选择地址(该地址位于堆栈之间)。 flag是一组标志位,一般也为0。调用成功后,返回指向共享内存第一个字节的指针。
      • shmdt(addr):将进程地址空间与该共享内存段分离,使该共享内存对当前进程而言不可用。
      • shmctl(shm_id, command, buf):控制共享内存。command参数:IPC_RMID(删除共享内存段)、IPC_STAT和IPC_SET(不常用)
    • 无关进程(非亲缘进程)共享内存的方法:
      • 使用XSI共享存储函数
      • 使用mmap将同一文件映射到多个进程的地址空间,为此要使用MAP_SHARED标志以保证:一个进程写到存储段,另一个进程可见。
    • 使用共享内存的优缺点:
      • 优点:方便,接口简单;数据不用传送而是直接读写内存,效率高;没有无名管道那种亲缘进程才能通信的限制,适用于不相关进程通信。
      • 缺点:需要借助外部的同步机制
    • 共享内存的使用例子,创建两个进程,shmwrite向共享内存写数据,shmread从共享内存读数据:
      • shmread进程,创建一块共享内存段,将共享内存段映射到自己的内存空间,从内存中读数据。
    #include <unistd.h>  
    #include <stdlib.h>  
    #include <stdio.h>  
    #include <sys/shm.h>
    struct shared_use_st  
    {  
        int wirte_read_flag;        //作为一个标志,非0:表示可读,0表示可写  
        char text[1024];              //记录写入和读取的文本  
    };
    int main()  
    {  
        int running = 1;    //程序是否继续运行的标志  
        void *shm = NULL;    //分配的共享内存的原始首地址  
        struct shared_use_st *shared;   //指向shm  
        int shmid;         //共享内存标识ID号  
        //创建共享内存,当key一样时返回的shmid也是一样的,则两个进程使用同一块共享内存,IPC_CREAT表示创建一块指定key的共享内存块
        shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);  
        if(shmid == -1)  
        {  
            fprintf(stderr, "shmget failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        //将共享内存连接到当前进程的地址空间  
        shm = shmat(shmid, 0, 0);  
        if(shm == (void*)-1)  
        {  
            fprintf(stderr, "shmat failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        printf("
    Memory attached at %X
    ", (int)shm);  
        //设置共享内存  
        shared = (struct shared_use_st*)shm;  
        shared->wirte_read_flag = 0;  //设为可写
        while(running)   //读取共享内存中的数据  
        {  
            //可读模式,从进程的地址空间shm里读就相当于从共享内存里读
            if(shared->wirte_read_flag != 0)  
            {  
                printf("Receive Message: %s", shared->text);  
                sleep(rand() % 3);  
                //读取完数据,设置wirte_read_flag使共享内存段可写  
                shared->wirte_read_flag = 0;  
                //输入了end,退出循环  
                if(strncmp(shared->text, "end", 3) == 0)  
                    running = 0;  
            }  
            else        //有其他进程在写数据,不能读取数据  
                sleep(1);  
        }  
        //把共享内存从当前进程中分离  
        if(shmdt(shm) == -1)  
        {  
            fprintf(stderr, "shmdt failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        //删除共享内存  
        if(shmctl(shmid, IPC_RMID, 0) == -1)  
        {  
            fprintf(stderr, "shmctl(IPC_RMID) failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        exit(EXIT_SUCCESS);  
    }  
      • shmwrite进程,取得共享内存,将共享内存映射到自己的内存空间,向内存中写数据。
    #include <unistd.h>  
    #include <stdlib.h>  
    #include <stdio.h>  
    #include <string.h>  
    #include <sys/shm.h>  
    struct shared_use_st  
    {  
        int wirte_read_flag;        //作为一个标志,非0:表示可读,0表示可写  
        char text[1024];              //记录写入和读取的文本  
    };
    int main()  
    {  
        int running = 1;  
        void *shm = NULL;  
        struct shared_use_st *shared = NULL;  
        char buffer[1024 + 1];  //用于保存输入的文本  
        int shmid;  
        //创建共享内存,当key一样时,返回的shmid也是一样的,则两个进程访问同一块共享内存,IPC_CREAT表示创建一块指定key的共享内存
        shmid = shmget((key_t)1234, sizeof(struct shared_use_st), 0666|IPC_CREAT);  
        if(shmid == -1)  
        {  
            fprintf(stderr, "shmget failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        //将共享内存连接到当前进程的地址空间  
        shm = shmat(shmid, (void*)0, 0);  
        if(shm == (void*)-1)  
        {  
            fprintf(stderr, "shmat failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        printf("Memory attached at %X
    ", (int)shm);  
        //设置共享内存  
        shared = (struct shared_use_st*)shm;  
        while(running)    //向共享内存中写数据  
        {  
            //数据还没有被读取,则等待数据被读取,不能向共享内存写
            while(shared->wirte_read_flag == 1)  
            {  
                sleep(1);  
                printf("Waiting...
    ");  
            }  
            //向共享内存中写入数据,向进程的地址空间shm里写就相当于往共享内存里写!  
            printf("Enter some text: ");  
            fgets(buffer, BUFSIZ, stdin);  
            strncpy(shared->text, buffer, 1024);  
            //写完数据,设置written使共享内存段可读  
            shared->wirte_read_flag = 1;  
            //输入了end,退出循环  
            if(strncmp(buffer, "end", 3) == 0)  
                running = 0;  
        }  
        //把共享内存从当前进程中分离  
        if(shmdt(shm) == -1)  
        {  
            fprintf(stderr, "shmdt failed
    ");  
            exit(EXIT_FAILURE);  
        }  
        sleep(2);  
        exit(EXIT_SUCCESS);  
    }  

    (ps:以上程序转自http://blog.csdn.net/ljianhui/article/details/10253345

  • 相关阅读:
    MySQL Sandbox安装使用
    主从复制延时判断
    Carthage
    QCon 2015 阅读笔记
    QCon 2015 阅读笔记
    Scrum&Kanban在移动开发团队的实践 (一)
    移动开发-第三方聊天服务
    开通博客
    spark的若干问题
    hadoop2.2.0安装需要注意的事情
  • 原文地址:https://www.cnblogs.com/ladawn/p/8875513.html
Copyright © 2011-2022 走看看