• 共享内存和信号量的配合机制


    进程之间共享内存的机制,有了这个机制,两个进程可以像访问自己内存中的变量一样,访问共享内存的变量。但是同时问题也来了,当两个进程共享内存了,就会存在同时读写的问题,就需要对于共享的内存进行保护,就需要信号量这样的同步协调机制。

    对于共享内存的操作,首先,创建之前,我们要有一个 key 来唯一标识这个共享内存。这个 key 可以根据文件系统上的一个文件的 inode 随机生成。

    然后,我们需要创建一个共享内存,就像创建一个消息队列差不多,都是使用 xxxget 来创建。其中,创建共享内存使用的是下面这个函数:

    int shmget(key_t key, size_t size, int shmflag);

    其中,key 就是前面生成的那个 key,shmflag 如果为 IPC_CREAT,就表示新创建,还可以指定读写权限 0777。

    对于共享内存,需要指定一个大小 size,这个一般要申请多大呢?一个最佳实践是,我们将多个进程需要共享的数据放在一个 struct 里面,然后这里的 size 就应该是这个 struct 的大小。这样每一个进程得到这块内存后,只要强制将类型转换为这个 struct 类型,就能够访问里面的共享数据了。

    在这里,我们定义了一个 struct shm_data 结构。这里面有两个成员,一个是一个整型的数组,一个是数组中元素的个数。

    生成了共享内存以后,接下来就是将这个共享内存映射到进程的虚拟地址空间中。我们使用下面这个函数来进行操作。

    void *shmat(int  shm_id, const  void *addr, int shmflg);

    这里面的 shm_id,就是上面创建的共享内存的 id,addr 就是指定映射在某个地方。如果不指定,则内核会自动选择一个地址,作为返回值返回。得到了返回地址以后,我们需要将指针强制类型转换为 struct shm_data 结构,就可以使用这个指针设置 data 和 datalength 了。

    当共享内存使用完毕,我们可以通过 shmdt 解除它到虚拟内存的映射。

    int shmdt(const  void *shmaddr);

    信号量以集合的形式存在的。

    首先,创建之前,我们同样需要有一个 key,来唯一标识这个信号量集合。这个 key 同样可以根据文件系统上的一个文件的 inode 随机生成。

    然后,我们需要创建一个信号量集合,同样也是使用 xxxget 来创建,其中创建信号量集合使用的是下面这个函数。

    int semget(key_t key, int nsems, int semflg);

    这里面的 key,就是前面生成的那个 key,shmflag 如果为 IPC_CREAT,就表示新创建,还可以指定读写权限 0777。

    这里,nsems 表示这个信号量集合里面有几个信号量,最简单的情况下,我们设置为 1。

    对于信号量,往往要定义两种操作,P 操作和 V 操作。对应上面代码中 semaphore_p 函数和 semaphore_v 函数,semaphore_p 会调用 semop 函数将信号量的值减一,表示申请占用一个资源,当发现当前没有资源的时候,进入等待。semaphore_v 会调用 semop 函数将信号量的值加一,表示释放一个资源,释放之后,就允许等待中的其他进程占用这个资源。

    可以用这个信号量,来保护共享内存中的 struct shm_data,使得同时只有一个进程可以操作这个结构。

    共享内存和信号量的配合机制,如下图所示:

    • 无论是共享内存还是信号量,创建与初始化都遵循同样流程,通过 ftok 得到 key,通过 xxxget 创建对象并生成 id;
    • 生产者和消费者都通过 shmat 将共享内存映射到各自的内存空间,在不同的进程里面映射的位置不同;
    • 为了访问共享内存,需要信号量进行保护,信号量需要通过 semctl 初始化为某个值;
    • 接下来生产者和消费者要通过 semop(-1) 来竞争信号量,如果生产者抢到信号量则写入,然后通过 semop(+1) 释放信号量,如果消费者抢到信号量则读出,然后通过 semop(+1) 释放信号量;
    • 共享内存使用完毕,可以通过 shmdt 来解除映射。

    此文章为11月Day20学习笔记,内容来源于极客时间《趣谈Linux操作系统》,推荐该课程。

  • 相关阅读:
    六、【React拓展】Component的2个效率问题
    Text to image论文精读PDF-GAN:文本生成图像新度量指标SSD Semantic Similarity Distance
    信息系统项目管理师 12题
    虹科示波器 | 汽车免拆检修 | 2015款奔驰G63AMG车发动机偶尔自动熄火
    4、创建第一个鸿蒙应用
    使用C/C++实现字典树(数组或者链表方式)
    数据库主键一定要自增吗?有哪些场景不建议自增?
    一个前端大佬的十年回顾 | 漫画前端的前世今生
    菜菜学paddle第四篇:改进卷积神经网络构建手写数字识别
    经典算法系列之(一):算法的基础概念,数据结构的基础概念,以及算法+数据结构=程序
  • 原文地址:https://blog.csdn.net/key_3_feng/article/details/134518632