★IPC方法包括管道(PIPE)、消息队列(Message_Queue)、旗语、共用内存(ShareMemory)以及套接字
(Socket)。进程间通信主要包括了管道、系统IPC(包括了消息队列、信号以及共享存储)、套接字(Socket)。
此文将叙述共享内存的相关内容。
在此之前先来看看关于进程的内存映像的相关内容。
一、进程的内存映像(区别于可执行程序文件):
指的是内核在内存中如何存放可执行程序文件。两者的区别表现在三个方面:①可执行程序是位于硬盘上的,而内存映像位
于内存上; ②可执行程序没有堆栈,因为只有当程序被加载到内存上的时候才会分配相应的堆栈;③可执行程序是静态的,因为它
还没运行,但是内存映像是动态的,数据是随着运行过程改变的。
Linux下的C程序生成进程的内存映像主要由四个步骤组成:预编译、编译、汇编、链接。编译器gcc经过预编译、编译、汇编
3个步骤将源程序文件转换成目标文件。如果程序有多个目标文件或程序中使用了库函数,则编译器还需要将所有目标文件及所需的
库文件链接起来,最后生成可执行程序。当程序执行时,操作系统将可执行程序复制到内存中。其布局如下图:
注:其中正文所在的区域为只读代码和只读数据区域,也就是通常所说的代码段,用来存放程序的执行代码,包括了
只读的常数变量,例如:字符串常量等。而未初始化的数据区域称为BSS(Block Started by Symbol)段,用来存
放未初始化的全局变量,属于静态内存分配的一部分。初始化的数据区域称为数据段,用来存放已初始化的全局变
量,也属于静态内存分配的一部分,所以一般习惯地将BSS段和数据段统称为数据段。
二、不同进程读取同一数据块时的地址分配
注:图中的地址空间为虚拟空间地址,可以看到不同的进程PCB1和PCB2读取相同的地址空间处时,通过页表和也表
描述符mmu分别指向了不同的物理地址,所以尽管表面上看起来两个进程访问的同一地址,其实际映射得到的物理
地址却并非如此。
三、共享内存
共享内存是指被多个进程共享的部分物理内存。一个进程向共享内存区域一旦写入了数据,共享这个内存区域
的所有进程就可以直接看到其中的内容。共享内存允许两个不相关的进程访问同一个逻辑内存,是两个正在运行的进
程之间共享和传递数据的一种非常有效的方式。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程
都可以访问共享内存中的地址,也就是说一旦进程改动共享内存中的数据时,会影响到访问该区域的其他进程。
★关于共享内存函数的声明,在头文件sys/shm.h中。
注:图中的红框部分表明了共享内存(shm)与进程间通信的类属关系,同样拥有ipc perm的结构体。白框则表明了共
享内存的四个常用操作函数。
1.shmat函数:
第一次创建完共享内存时,不能被任何进程访问,shmat函数的作用就是用来启动对该共享内存的访问,并把共
享内存连接到当前进程的地址空间。其原型如下图:
注:可以看到,该函数中有三个形参,shm_id是由shmget函数返回的共享内存标识;shm_addr指定共享内存连接
到当前进程中的地址位置,一般为空,表示让系统来选择共享内存的地址;shm_flg是一组标志位,通常为0。其返
回值调用成功时返回一个指向共享内存第一个字节的指针,如果调用失败则返回-1。
2.shmctl函数:
与信号量的semctl函数一样,用来控制共享内存,其原型如下图:
注:shmctl函数中同样具有三个形参,shm_id是shmget函数返回的共享内存标识符;command是要采取的操
作,可取三个值 :①IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关
联值覆盖shmid_ds的值;②IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中
给出的值;③IPC_RMID:删除共享内存段。buf是一个结构指针,它指向共享内存模式和访问权限的结构。
3.shmdt函数:
用于将共享内存从当前进程中分离。(注:将共享内存分离并不是删除它,只是使该共享内存对当前进程不再
可用)。其原型见下图:
注:参数shmaddr是shmat函数返回的地址指针,其返回值调用成功时返回0,失败时返回-1。
4.shmget函数:
用于创建共享内存,其函数原型见下图:
注:该函数拥有三个形参,key与信号量的semget函数一样,程序需要提供一个参数key(非0整数),有效地为共
享内存段命名,shmget函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函
数,调用失败则返回-1;size以字节为单位指定需要共享的内存容量;shmflg是权限标志,它的作用与open函数的
mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做“或”操作。共享内
存的权限标志与文件的读写权限一样。
▲不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内
存的访问都是间接的,程序先通过调用shmget函数并提供一个键,再由系统生成一个相应的共享内存标识符
(shmget函数的返回值),只有shmget函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回
的信号量标识符。
★练习:创建两个进程,在A进程中创建一个共享内存,并向其写入数据,通过B进程从共享内存中读取数据。
1.shm_comm.h文件:
2.read_process.c文件:
3.write_process.c文件:
4Makefile自动化编译文件:
★运行结果:
★总结:
共享内存特点:
①进程间通信中速度最快的,且需要被挂起。原因:写在共享内存区的文件中的数据内容可以直接由共享双方直接访问,没有数据拷贝的时间消耗,所以速度很快。
②不提供任何的同步和互斥机制,须用户自主维护(可通过信号量及设置同步机制等手段)。
③接口较为简单。