在我们学习嵌入式课程里面的进程线程这一章节的时候,不可避免的会遇到通讯的问题,我们知道线程他们之间的数据是可以共享的,但是进程是相互独立的,那么进程与进程之间能进行数据交互么?又有哪些方式呢?我们接着往下看
首先进程之间也是可以进行通讯的,他的通讯方式也有很多,比如说:共享内存、消息队列、信号量、信号、管道等等,每一种通讯方式都有自己的优缺点。今天我们着重了解一下共享内存这一方式
1、什么是共享内存?
答:共享内存是一种进程间的通讯方式。它允许两个或者更多进程访问同一块内存,就如同malloc函数向不同进程返回了指向同一个物理内存区域的指针。共享内存是Unix/Linux 下多进程之间的通信方式,这种方法通常用于一个程序的多进程间通信,实际上多个程序间也可以通过共享内存来传递信息。并且共享内存是最快的IPC 形式。一旦这样的内存映射到共享它的进程进程的地址空间,这些进程数据传递将不会再设计到内核,也就是说进程不用通过执行进入内核的系统调用来传递彼此的数据
2、如何实现共享内存的呢?
答:首先我们需要明白,进程间通信的前提:先让不同的进程,看到同一份资源。而共享内存就是通过进程可以看到同一块内存而实现的
每一个进程都有一个虚拟的地址空间,在地址空间的栈区和堆区中间有一块很大的内存,叫共享区,在用户申请共享内存时,操作系统在物理内存种申请一块空间,然后映射到页表种,页表建立联系后,在映射到各自的共享区种。两个进程共同映射的物理内存操作就叫共享内存
基本编写
首先如果我们要实现共享内存,需要四个接口:
从操作系统角度:1、创建空闲内存 2、删除共享内存
进程角度:3、关联共享内存 4、去关联共享内存
创建共享内存
·参数
·参数
key:这个共享内存段名字,与信号量的semget函数一样,程序需要提供一个参数key(非0整数),它有效地为共享内存段命名,shmget()函数成功时返回一个与key相关的共享内存标识符(非负整数),用于后续的共享内存函数。调用失败返回-1.。
不相关的进程可以通过该函数的返回值访问同一共享内存,它代表程序可能要使用的某个资源,程序对所有共享内存的访问都是间接的,程序先通过调用shmget)函数并提供一个键,再由系统生成一个相应的共享内存标识符(shmget()函数的返回值),只有shmget()函数才直接使用信号量键,所有其他的信号量函数使用由semget函数返回的信号量标识符。
size:共享内存以字节为单位指定需要共享的内存容量。
共享内存以字节为单位指定需要共享的内存容量。
这个大小以字节为单位。实现通常将其向上取为系统页长的整数倍,如果应用指定的size值并非系统页长的整数倍,那么最后一页的余下部分是不可使用的。
这个大小以字节为单位.实现通常将其向上取为系统页长的整数倍,如果应用指定的Size值并非系统页长的整数倍,那么最后一页的余下部分是不可使用的.
如果创建一个新段(通常在服务器进程中),则必须指定其size。如果正在引用一个现存的段(一个客户进程),则将size指定为0,。当创建一个新段是,段内的内容初始化为0。
shmflg:shmflg是权限标志,由九个权限标志构成,它们的用法和创建文件时使用mode模式标志是一样的。它的作用也与open函数的mode参数一样,如果要想在key标识的共享内存不存在时,创建它的话,可以与IPC_CREAT做或操作。共享内存的权限标志与文件的读写权限一样,举例来说,0644,它表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,同时其他用户创建的进程只能读取共享内存。
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1
shmat函数:
shmid :共享内存标识
shmaddr:指定连接的地址
shmflg :它的两个可能取值是SHM_RND和SHM_RDONLY
返回值:成功返回一个指针,指向共享内存第一个字节;失败返回-1。如果shmat成功执行,那么内核将使与该共享存储段相关的shmid_ds结构中的shm_nattch计数器值加1。
注意:
shmaddr为NULL,则此段连接到由内核选择的一个可用地址上,则是推荐的使用方式。shmaddr不为NULL且 shmfilg 无 SHM_RND标记,则以shmaddr为连接地址。
shmaddr不为NULL且shmfig设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。
公式: shmaddr - (shmaddr % SHMLBA)
除非只计划在一种硬件上运行应用程序(这在当今是不大可能的),否则不应指定共享内存段所连接到地址。而是应当指定shmaddr为NULL,以便由系统来选择地址。
shmflg=SHM_RDONLY,表示连接操作用来只读共享内存,否则以读写方式连接此段。
当对共享内存的操作结束时,则调用shmdt与该段分离。注意:这不从系统中删除其标识符以及相关的数据结构。该标识符依然存在,直至某个进程(一般是服务器进程)带IPC_RMID命令的调用shmctl特地删除它为止。
Shmdt 函数
功能: 将共享内存段与当前进程脱离
原型:int shmdt(const void *shmaddr)
参数:
Shmaddr 由 shmat 所返回的指针
返回值:成功返回0,失败返回-1
注意:将共享内存段与当前进程脱离不等于删除共享内存段
shmctl函数
·功能:用用于控制共享内存
原型int shmctl(int shmid, int cmd,struct shmid_ds *buf);。
参数
shmid:由shmget返回的共享内存标识码
cmd:将要采取的动作(有三个可取值)
IPC_STAT: 取此段的shmid_ds 结构,并将它存在由buf 指向的结构中
IPC_SET:按buf指向的结构体中的值设置与此共享存储段相关的shmid_ds结构中的字段。
IPC_RMID:从系统中删除该共享内存
buf:指向一个保存这共享内存的模式状态和访问权限的数据结构
返回值: 成功返回0,失败返回-1