接下来的进程间通讯机制
就是共享内存
共享内存很特殊
它是一个快捷方便的本地通讯机制
它的出现比较晚
比管道 比进程信号量都要晚
共享内存有一点
在编程的时候是需要特别注意的
系统是没有对共享内存操作
定义任何同步行为的
缺省同步行为是不存在的
所以如果你需要
你就必须自主地设定
共享内存的同步行为和同步策略
你自己要能够做到这一点
典型的方式 比如讲进程信号量
我就可以做这个事
共享内存在使用的过程中
它有一个一定的逻辑
有一个规则
就是一个进程会分配一段共享内存区段
那么其它的进程呢
如果需要访问这个共享内存呢
就会查询、连接这个内存区段
这个动作我们称它为attach 叫连接
你完成了这个共享内存访问之后呢
你就可以不要了
就不连接了嘛 就拆卸
就datach这个内存区段
在某一个特定的时刻
如果所有的进程都不用这个共享内存了
那么你就可以释放共享内存区段
是按照这个模式进行工作的
在Linux操作系统下边
每一个进程 它的虚拟地址空间
是按照页进行编址的
缺省值 一个页面是4KB大小
也就是4096个字节
注意不同的硬件架构
和不同的操作系统可能是不一样的
现在我们用的是Intel 386那个架构
我们的个人电脑
它用的那个页面架构是4096个字节
你可以使用getpagesize()这个函数
来获取当前系统下页面的尺寸
每个进程都会维持从内存地址
到虚拟的这个页面地址的一个映射
多个进程可能使用同一个虚拟页面
但是同样的数据在不同的进程里边
它的地址可能并不是一样的
这有一个地址映射和变换的问题
这个地方是需要特别去注意的
你如果分配一个新的共享内存
它就会创建一个新的内存页面
其它进程呢
就可以连接这个共享内存来访问它
这样两个进程之间
不就可以通过共享内存进行通讯了吗
这是共享内存能够工作的
重要的一个地方
共享内存区段本身的分配
只能由一个进程来负责
释放也一样 你如果多个进程
都负责去管理这个共享内存区段
那不就乱了套了吗 这是不行的
这个是需要特别注意的地方
我们使用shared memory get
shmget()这个函数
来获取和分配一段共享内存
这个函数的格式和那个semget()特像
函数名字就把“h”替换了“e”
你注意看 它有一个key参数
有一个size参数 有一个shmflg参数
key还是键值
表示这个共享内存区段的
这样一个整数键值
size就是你想分配多大的
存储空间的共享内存
一般来讲 应该是页面的整数倍
4096个字节的整数倍
shmflg 就是创建这个共享内存区段的时候
它的创建标志 它特定的位标志
一般来讲 我们会使用IPC_CREAT来创建它
如果使用IPC_EXCL
这是一个独占式的创建
后者呢 就这个IPC_EXCL
会和IPC_CREAT合并使用的
如果这个键值已经使用了
那么创建就会失败了
这个很典型
如果你没有IPC_EXCL
那么它就会创建这个键值
发现这个键值已经创建了 OK
它就直接返回
那个共享内存区段的那个ID就完了
你就完成了共享
它实际上是查询一个
已经创建好的共享内存
有一些特定的位标志
可以在创建共享内存中使用
尤其是涉及到
一些用户的读写权限的地方
包括宿主用户 包括组用户
包括其他用户
你可以设定它
你比如讲 我们可以shmget()
设置一个shm_key传进去
然后get page size() 得到页的尺寸
然后以IPC_CREAT | S_IRUSR | S_IWUSER
就用户可读写的 像这样一个模式
创建一个共享内存区段
得到共享内存区段的seg_id
它的ID标识符
使用shmat()这个函数连接共享内存
传共享内存的ID
传共享内存的基地址
传连接的标志
使用shmdt() 就是detach
拆卸这个共享内存区段
你不用了 你就把它拆卸就完了
只需要传它的基地址就OK了
我们看一个具体的例子
定义一个shmid_ds的
这样一个数据结构shmbuf
然后定义一个整型seg_size
我们把共享内存区段的尺寸
固定为0x6400 这么大
然后调用shmget()
创建这个共享内存区段
创建完成之后
我们调用shmat()来连接这个共享内存区段
连接完了以后呢
我们就得到了这个共享内存区段的基地址
把它转型成指向字符指针之后
我们就可以操纵这个共享内存区段了
把它当做一个字符串一样操纵它就完了
我们就可以朝里面写入数据
当然在此过程中
可以调用shmctl()这个函数
控制那个共享内存 这是可以
这一点倒和semctl()是一样的
这是shmctl() 你可以控制它
可以得到它的信息
我们这里边用IPC_STAT得到它的信息
接下来我们可以
向共享内存区段写入数据
传那个基地址shared_mem进去
就可以向那个缓冲区里面写数据了
这个写入就好像你定义了
一个字符数组
或者是定义一个字符指针
然后new一段存储区出来
朝里面写数据 一样
然后用完了
shmdt() 就把shared_mem清掉
接下来可以重新地
把它连接到一个新的不同的区段
shared__mem 可以
然后重新连接 重新去访问它
用完了 再把它detach掉 OK
最后销毁它
用shmctl()调用传IPC_RMID
销毁这个ID所对应的共享内存区段
释放它 OK
这就是使用共享内存的最基本的策略