由浅入深探讨Linux进程间通信(中篇)

由浅入深探讨Linux进程间通信(中篇)

目录

前言

上一篇文章由浅入深探讨Linux进程间通信(上篇)只讲解到了进程间通信方法之管道,这一篇文章继续讲解System V进程间通信,话不多说直接开始。

1.System V进程间通信实现原理

由浅入深探讨Linux进程间通信(中篇) 图1

System V进程间通信需要借助Linux命名空间来实现。

1.1 什么是Linux命名空间?

Linux命名空间是一种虚拟化技术,它提供了一种轻量级的虚拟化方式,可以将一个系统中的全局资源隔离开来,使得不同的进程可以拥有自己独立的资源视图。命名空间其实就是一些列资源的集合,每个进程都需要指向这个集合,不同的进程如果指向相同的命名空间,那么进程间就能共享命名空间资源。命名空间内核定义如下:

由浅入深探讨Linux进程间通信(中篇) 图2

System V进程间通信需要用到IPC命名空间。IPC命名空间有一个数组成员ids,该成员主要用来存储消息队列,信号量,共享内存IPC对象。 System V三种进程间通信方式(消息队列,信号量,共享内存)都是基于IPC对象实现,消息队列,信号量,共享内存都继承了IPC对象(kern_ipc_perm),学习System V进程间通信首先我们得知道IPC对象如何创建和销毁。 1.2 IPC对象创建和销毁 IPC对象创建和销毁需要通过键值(Key)来完成。什么是IPC键值(Key)? IPC键值(Key)是一个整型值,用于唯一标识一个IPC对象,在创建IPC对象时,需要指定一个IPC键值,进程可以使用这个IPC键值来访问该IPC对象,同一个IPC键值只能对应一个IPC对象,不同的IPC键值对应不同的IPC对象。 创建IPC对象时,首先得生成一个IPC Key,IPC Key有以下三种生成方式:

  1. 使用一个随机的整数。
  2. 使用IPC_PRIVATE标志生成,此种方法只能用于有亲缘关系进程。
  3. 使用ftok函数生成。

生成Key后,通过Key索引ipc_namespace->ids->key_ht(哈希表),Key主要是用来索引哈希表,如果哈希表中已经有IPC对象,直接返回IPC对象ID,否则需要创建一个新的IPC对象,并为新的IPC生成对象ID,再把IPC对象插入哈希表,新的IPC对象会以IPC对象ID为索引,插入ipc_namespace->ids->ipcs_id(radix树)。同样IPC对象销毁也是通过Key删除哈希表IPC对象记录。 什么是IPC对象ID? IPC对象ID是一个整数标识符,用于标识System V IPC对象(如消息队列、信号量和共享内存),IPC对象ID是由内核分配的,IPC对象主要用来索引ipc_namespace->ids->ipcs_id(radix树),radix树主要用来加快查询效率。

2.System V消息队列

由浅入深探讨Linux进程间通信(中篇) 图3

有了前面的铺垫,我们就很容理解消息队列,信号量,共享内存的实现。

  • 消息队列创建

msgget函数通过Key创建消息队列并返回IPC对象ID。

  • 发送消息

得到IPC对象ID后,就能通过调用msgsnd函数发送消息,发送的消息存储在msg_queue(消息队列)->q_messages(队列)。

  • 接收消息

通过msgrcv函数接收消息,msgrcv函数从msg_queue(消息队列)->q_messages(队列)读取消息。两个进程因为都指向相同的IPC命名空间,所以两个进程通过相同的Key返回同一个IPC对象ID,有了相同的ID就能通过ID进行消息发送和接收。

3.System V信号量

由浅入深探讨Linux进程间通信(中篇) 图4

  • 信号量创建

semget函数通过Key创建信号量并返回IPC对象ID。

  • 信号量PV操作

semop函数实现信号量PV操作。

  • 信号量销毁

semctl函数通过IPC_RMID命令销毁信号量。 System V信号量(sem_array)维护的是信号量数组,也就是同时支持多个信号量,所以在初始化信号量时需指定信号量数量,操作信号量时需通过数组下标指定操作的是哪个信号量。 4.System V共享内存

由浅入深探讨Linux进程间通信(中篇) 图5

  • 共享内存创建

semget函数通过Key创建共享内存并返回IPC对象ID。

  • 共享内存映射

通过shmat函数实现内存映射,通过同一共享文件完成内存映射的内存区域,进程间可以相互访问。

  • 数据拷贝

完成共享内存映射后,就能通过普通的内存拷贝函数,如:memcpy函数,实现数据的写入和读取,完成进程间通信。

  • 取消共享内存内存映射

通过shmdt函数取消内存映射。

  • 共享内存销毁

shmctl函数通过IPC_RMID命令销毁信号量。System V共享内存(shmid_kernel)维护的是一个struct file对象(shm_filesem),shm_filesem为共享内存文件,用来实现内存映射,不同的进程通过相同的shm_filesem共享内存文件完成内存映射后,就能访问同一块物理内存区域,从而实现进程间通信。最后思考一下:System V进程间通信方法为什么满足进程间通信要求? IPC对象属于内核空间的一块内存区域,进程(task_struct对象)能够通过IPC命名空间表访问这块内存区域,所以System V进程间通信方法满足进程间通信要求。

← 返回文章列表