博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux进程间通信---共享内存
阅读量:4677 次
发布时间:2019-06-09

本文共 4739 字,大约阅读时间需要 15 分钟。

  • 共享内存允许多个进程共享一个给定的内存空间,进程可以直接读写内存,因此是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 
#include
#include
#include
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\n"); exit(EXIT_FAILURE); } //将共享内存连接到当前进程的地址空间 shm = shmat(shmid, 0, 0); if(shm == (void*)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("\nMemory attached at %X\n", (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\n"); exit(EXIT_FAILURE); } //删除共享内存 if(shmctl(shmid, IPC_RMID, 0) == -1) { fprintf(stderr, "shmctl(IPC_RMID) failed\n"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); }
    • shmwrite进程,取得共享内存,将共享内存映射到自己的内存空间,向内存中写数据。
#include 
#include
#include
#include
#include
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\n"); exit(EXIT_FAILURE); } //将共享内存连接到当前进程的地址空间 shm = shmat(shmid, (void*)0, 0); if(shm == (void*)-1) { fprintf(stderr, "shmat failed\n"); exit(EXIT_FAILURE); } printf("Memory attached at %X\n", (int)shm); //设置共享内存 shared = (struct shared_use_st*)shm; while(running) //向共享内存中写数据 { //数据还没有被读取,则等待数据被读取,不能向共享内存写 while(shared->wirte_read_flag == 1) { sleep(1); printf("Waiting...\n"); } //向共享内存中写入数据,向进程的地址空间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\n"); exit(EXIT_FAILURE); } sleep(2); exit(EXIT_SUCCESS); }

(ps:以上程序转自)

转载于:https://www.cnblogs.com/ladawn/p/8875513.html

你可能感兴趣的文章
Navicat远程连接阿里云服务器的mysql
查看>>
https soap链接示例
查看>>
八LWIP学习笔记之用户编程接口(NETCONN)
查看>>
Git Day02,工作区,暂存区,回退,删除文件
查看>>
Windows Phone 7 Coding4Fun控件简介
查看>>
Nginx 常用命令总结
查看>>
hall wrong behavior
查看>>
Collection集合
查看>>
【C++】const在不同位置修饰指针变量
查看>>
github新项目挂历模式
查看>>
编写jquery插件
查看>>
敏捷开发笔记
查看>>
学前班
查看>>
关于自关联1
查看>>
hdu-1814(2-sat)
查看>>
谷歌浏览器,添加默认搜索引擎的搜索地址
查看>>
数据结构化与保存
查看>>
为什么需要Docker?
查看>>
国内5家云服务厂商 HTTPS 安全性测试横向对比
查看>>
how to control project
查看>>