linux基础编程:进程通信之System V IPC:消息队列,信号量,共享内存

本文介绍了Linux下的System V IPC,包括消息队列、信号量和共享内存的原理和API应用。System V IPC是内核级别的通信机制,持久存在于内核中,不同于管道和信号。文章详细阐述了三种通信机制的结构体、关键属性以及用户空间的操作函数,为理解Linux进程间通信提供了深入的见解。
摘要由CSDN通过智能技术生成

Linux下的进程通信基本上是从Unix平台上的进程通信手段继承而来的。而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间通信方面的侧重点有所不同。前者对Unix早期的进程间通信手段进行了系统的改进和扩 充,形成了“system V IPC”,通信进程局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。Linux则把两者继承了下来,如图示:



其中,最初Unix IPC包括:管道、FIFO、信号;System V IPC包括:System V消息队列、System V信号灯、System V共享内存区;Posix IPC包括: Posix消息队列、Posix信号灯、Posix共享内存区。有两点需要简单说明一下:1)由于Unix版本的多样性,电子电气工程协会(IEEE)开 发了一个独立的Unix标准,这个新的ANSI Unix标准被称为计算机环境的可移植性操作系统界面(PSOIX)。现有大部分Unix和流行版本都是遵循POSIX标准的,而Linux从一开始就遵 循POSIX标准;2)BSD并不是没有涉足单机内的进程间通信(socket本身就可以用于单机内的进程间通信)。事实上,很多Unix版本的单机 IPC留有BSD的痕迹,如4.4BSD支持的匿名内存映射、4.3+BSD对可靠信号语义的实现等等。

在文章《linux基础编程:进程通信之信号》和《linux基础编程:进程通信之管道》两篇文章中介绍了最初的Unix IPC通信机制。通过对这两种方式的理解,我们知道管道和信号都是随着进程持续而存在(IPC一直存在到打开IPC对象的最后一个进程关闭该对象为止),如果进程结束了,管道和信号都会关闭或者丢失。下面将会分别介绍基于System V IPC的通信机制:消息队列,信号灯,共享内存区。基于System V IPC的通信机制的特点是:它是随着内核的持续而存在(IPC一直持续到内核重新启动或者显示删除该对象为止)。本文将介绍System V IPC 在内核中实现的原理和以及相应的API,应用。


System V IPC原理


首先基于System V IPC的通信是基于内核来实现。首先我们来分析整个System V IPC的结构。在linux 3.6.5内核源码中我们可以在/include/linux/ipc_namespace.h文件中找到struct ipc_namespace这个结构体,该结构体是基于System V IPC 三种通信机制的命名空间或者说全局入口,在该结构体中定义了一个struct ipc_ids ids[3]结构体数组,关键的结构体代码如下:

struct ipc_namespace {
	atomic_t	count;
	struct ipc_ids	ids[3];
	...
};
struct ipc_ids {
	int in_use;
	unsigned short seq;
	unsigned short seq_max;
	struct rw_semaphore rw_mutex;
	struct idr ipcs_idr;
};
每一个struct ipc_ids结构体对应System V IPC 每一种通信机制,struct ipc_ids ids[3]就对应了三种IPC(msg_ids消息队列,sem_ids信号量,shm_ids共享内存区)。通过下面宏定义可以分别得到三种IPC结构体:

#define IPC_SEM_IDS     0
#define IPC_MSG_IDS     1
#define IPC_SHM_IDS     2
#define msg_ids(namespace)     ((namespace)->ids[IPC_MSG_IDS])
#define sem_ids(namespace)     ((namespace)->ids[IPC_SEM_IDS])
#define shm_ids(namespace)     ((namespace)->ids[IPC_SHM_IDS])
每一个struct ipc_ids结构体对应System V IPC 每一种通信机制,struct ipc_ids结构体中struct idr结构体记录了该IPC所有条目(比如:如果是消息队列,此时idr中记录了系统中当前所有消息队列的信息)。在文件/include/linux/idr.h中定义struct idr结构体,它是一种类似数组的内存区域。在IPC通信中,我们把该数组的每一项条目存储内容为struct kern_ipc_perm的结构体的指针。通过/ipc/util.c文件中的int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)函数,可以把struct kern_ipc_perm结构体指针添加到相对应的struct ipc_ids的struct idr中,此时struct kern_ipc_perm*就指向相应的IPC的一个条目,其结构体定义如下:
struct kern_ipc_perm
{
	spinlock_t	lock;
	int		deleted;
	int		id;
	key_t		key;
	uid_t		uid;
	gid_t		gid;
	uid_t		cuid;
	gid_t		cgid;
	umode_t		mode; 
	unsigned long	seq;
	void		*security;
};

对于每一种IPC具体的条目中,struct kern_ipc_perm为相应条目的第一个元素,得到struct kern_ipc_perm的指针的头指针,就相当于得到相应条目的头指针,以消息队列为例子代码如下。struct kern_ipc_perm结构体中的key_t key为该条目的唯一的key标识符。struct kern_ipc_perm结构体中还定义对应的ipc的特征信息(uid用户ID等)。

struct msg_queue {
	struct kern_ipc_perm q_perm;
	....
};

通过前面描述的内容,我们可以得到到每一个IPC条目的索引,下面我们将介绍具体的IPC条目的存储内容。


消息队列

消息队列就是一个消息的链表。可以把消息看作一个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读走消息。消息队列是随内核持续的,记录消息队列的数据结构位于内核中,只有在内核重起或者显示删除一个消息队列时,该消息队列才会真正被删除。
通过上面的分析我们知道通
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值