700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > linux进程间通信:system V 共享内存

linux进程间通信:system V 共享内存

时间:2018-06-04 23:31:04

相关推荐

linux进程间通信:system V 共享内存

文章目录

思维导图如下通信原理优势运行流程编程接口编程实例

思维导图如下

通信原理

多个进程共享物理内存的同一块区域(通常称之为“段”:segment)抛弃了内核态消息转存处理的过程,让两个进程直接通过一块内存进行通信

我们普通的像PIPE,FIFO,消息队列等的通信方式如下图:

这种方式的通信不论读写,都需要内核态(系统调用 read,write,pipe,mkfifo,msgget,msgsnd,msgrcv等)的介入,而且都需要经过数据从虚拟地址空间到物理地址空间的拷贝。

而共享内存的通信方式则都避免了以上的通信问题,直接为两个进程开辟相同的内存空间进行数据交互。

优势

减少了内存的拷贝(从用户拷贝到内核,从内核拷贝到用户)减少了2次系统调用(系统调用比较消耗性能,因为CPU处理系统调用时需要从用户态切换到内核态),提高了系统性能

运行流程

获取共享内存对象的ID将共享内存映射至本进程虚拟内存空间的某个区域(每个用户进程操作系统都有3G的虚拟进程空间)不同进程对这块内存进行读写、传输数据当进程不再使用这块共享内存时,解除映射关系当没有进程需要共享内存的时候,则删除该共享内存

编程接口

获取共享内存的对象ID ,创建或打开一个共享内存对象

a. 头文件<sys/types.h> <sys/shm.h>

b.int shmget (key_t key, size_t size, int shmflg);

c. 函数参数

keyIPC对象的键值,一般为IPC_PRIVATE 或者ftok返回的key值size共享内存的大小,一般为物理内存页(4K)的整数倍shmflg

IPC_CREAT :如果不存在指定的key值,那么就创建一个

IPC_EXCL: 若key值指定的内存存在,且指定了IPC_CEAT,则回复EXIST错误

IPC_HUGETLB 使用巨页(huge page)

d. 返回值:共享内存的标识ID

映射共享内存:

a. 头文件<sys/shm.h>

b.void *shmat(int shmid,const void *shmaddr,int shmflg);

c. 功能:将shmid标识的共享内存引入到当前进程的虚拟地址空间

d. 函数参数:

shmid共享内存的IPC对象IDshmaddr

若为NULL:共享内存会被attach到一个合适的虚拟地址空间,建议使用NULL

不为NULL:系统会根据参数以及地址边界对齐等分配一个合适的地址shmflg

IPC_RDONLY:附加只读权限,不指定的话返回默认是读写权限

IPC_REMAP:替换位于shmaddr处的任意既有映射(共享内存的段或者内存映射)

SHM_RND:将shmaddr四舍五入为SHMMLBA字节的倍数

e. 返回值:共享内存段的地址

解除共享内存映射

a. 头文件<sys/shm.h>

b.int shmdt(const void * shmaddr);

c. 功能:解除内粗映射,将共享内存分离出当前进程的地址空间

d. 函数参数:

shmaddr共享内存地址

e. TIPS:

通过fork创建的子进程会继承父进程所附加的共享内存,父子进程可以通过共享内存进行IPC通信,在exec系统调用中,所有附加的共享内存段都会被分离函数shmdt仅仅是使进程和共享内存脱离关系,将共享内存的引用计数是减1当共享内存的引用计数为0的时候,调用shmctl的IPC_RMID命令才会删除共享内存

设置共享内存属性

a. 头文件<sys/shm.h>

b.int shmctl(int shmid,int cmd,struct shmid_ds *buf);

c. 函数功能:获取/设置共享内存对象属性

d. 函数参数

-shmid共享内存对象的ID

-cmd:

IPC_RMID :删除共享内存及关联的shmid_ds数据结构

IPC_STAT: 将该共享内存关联的shmid_ds数据结构拷贝到参数buf中

IPC_SET: 使用buf中的数据更新与该共享内存对象相关联的shmid_ds

IPC_INFO:获取系统共享内存相关的信息

IPC_LOCK: 将一个共享内存段锁进内存,防止被swap出去

IPC_UNLOCK: 将一个共享内存解锁

shmid_ds *buf数据结构如下

struct shmid_ds {struct ipc_perm shm_perm;/* operation permissions */int shm_segsz; /* size of segment in bytes */pid_t shm_lpid;/* pid of last shm op */pid_t shm_cpid;/* pid of creator */short shm_nattch; /* # of current attaches */time_t shm_atime; /* last shmat() time*/time_t shm_dtime; /* last shmdt() time */time_t shm_ctime; /* last change by shmctl() */void *shm_internal; /* sysv stupidity */};

编程实例

写端shm_write.c:

#include<stdio.h>#include <unistd.h>#include <stdlib.h>#include <strings.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int main(){//key_t key = ftok("./",111);key_t key = 12345;//根据key值生成共享内存对象的唯一标识int shm_id = shmget(key,4096,IPC_CREAT|0666);//将当前进程加入共享内存,这里设置共享内存地址为NULL时//系统会自动为当前进程分配一个合适的内存空间,并返回共享内存的地址char *shm_p = shmat(shm_id , NULL, 0);memset (shm_p,0,4096);//从标准输入获取内容到共享内存的地址fgets(shm_p,4096,stdin);//等待输入完成,删除共享内存sleep(10);//当前进程创建的共享内存引用计数为0的时候,删除共享内存shmctl(shm_id,IPC_RMID,NULL);return 0;}

读端shm_read.c

#include<stdio.h>#include <unistd.h>#include <stdlib.h>#include <strings.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>int main() {// key_t key = ftok("./",111);key_t key = 12345;int shm_id = shmget(key, 4096, 0666);//和写端访问到了相同的共享内存区域,并获取内容存放到指针变量char *shm_p = shmat(shm_id , NULL, 0);printf("From SHM: %s\n",shm_p);//删除当前进程与共享内存的映射关系,同时共享内存的引用计数减一shmdt(shm_p);return 0;}

通过命令ipcs -m可以查看系统共享内存

需要先执行写入,再去运行读端读出;以上输出如下:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。