IPC机制之消息队列

消息队列分类

常用的消息队列分为以下两类:

  1. System V IPC之消息队列
  2. POSIX消息队列

1.System V IPC之消息队列

IPC数据结构是在进程请求IPC资源(信号量、消息对列或者共享内存区)时创建的。每个IPC资源都是持久的:除非被进程显示地释放,否则永远驻留在内存中(直到系统关闭)。IPC资源可以由任一进程使用,包括哪些不共享祖先进程所创建的资源的进程。
IPC标识符–每个IPC资源都是使用一个32位的IPC关键字来标识的。IPC标识符由内核分配给IPC资源,在系统内部是唯一的,而IPC关键字可以由程序员自由地选择。(摘自:深入理解linux内核,p780,关于System V IPC)

不管是进程之间还是同一个进程的不同线程之间要通过一个IPC资源进行通信时,这些进程或者同一进程的不同线程都要引用该资源的IPC标识符。

  • 使用System V IPC资源之消息队列,需要调用msgget()函数创建IPC资源。
    假设两个独立的进程想共享一个公共的IPC资源,可以使用两种方法:

  • 简单做法:这两个进程统一使用固定的、预定义的IPC关键字。【例外:假设另一个无关的程序也可能使用了相同的IPC关键字。在这种情况下,IPC函数可能被成功地调用,但返回错误资源的IPC标识符。】

  • 一个进程通过指定IPC_PRIVATE作为自己的IPC关键字来调用msgget()函数。一个新的IPC资源因此而被分配,这个进程可以与应用程序中的另一个进程共享自己的IPC标识符,或者自己创建另一个进程。这种方法确保IPC资源不会偶然被其他应用程序使用。

IPC资源的管理(通过数据结构)
IPC资源的每种类型(信号量、消息队列和共享内存区)都拥有ipc_ids数据结构,该结构的如下所示:

/*path--linux-3.18.132\include\linux\ipc_namespace.h*/
struct ipc_ids {
	int in_use;					/*已分配IPC资源数*/
	unsigned short seq;			/*下一分配位置使用的序号*/
	struct rw_semaphore rwsem;	/*保护ipc_ids数据结构体的信号量*/
	struct idr ipcs_idr;
	int next_id;
};

struct idr {
	struct idr_layer __rcu	*hint;	/* the last layer allocated from */
	struct idr_layer __rcu	*top;
	int			layers;	/* only valid w/o concurrent changes */
	int			cur;	/* current pos for cyclic allocation */
	spinlock_t		lock;
	int			id_free_cnt;
	struct idr_layer	*id_free;
};

/*使用ipcs -a命令可以查看IPC资源使用情况*/
root@ubuntu:/home# ipcs -a
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x00000000 294912     zhujinlin  600        524288     2          dest         
0x00000000 1671169    zhujinlin  600        1048576    2          dest         

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages  
System V IPC()系统调用

所有的IPC函数都必须通过适当的Linux系统调用实现。当进程调用一个IPC函数时,比如说msgget(),该函数实际上调用C库函数中的一个封装函数,该函数又通过传递msgget()的所有参数加上一个适当的子命令代码来调用ipc()系统调用。sys_ipc()服务例程检查子命令代码,并调用内核函数实现所请求的服务。

消息队列阻塞进程的条件

当消息队列满时(1.达到了最大消息数;2.达到了队列最大字节数),则试图让新消息入队的进程可能被阻塞。有可能引发异常情况,这点在使用过程中需要注意。

2.POSIX消息队列

POSIX标准基于消息队列定义了一个IPC机制,就是大家知道的POSIX消息队列。与System V IPC消息队列相比,具有许多优点:

  • 更简单的基于文件的应用接口
  • 完全支持消息优先级(优先级最终决定在队列中的消息的位置)
  • 完全支持消息到达的异步通知,这通过信号或是线程创建实现
  • 用于阻塞发送与接收的超时机制
/*path --glibc-2.18\rt\mq_send.c*/
/* Add message pointed by MSG_PTR to message queue MQDES.  */
int
mq_send (mqd_t mqdes, const char *msg_ptr, size_t msg_len,
	 unsigned int msg_prio)
{
  return mq_timedsend (mqdes, msg_ptr, msg_len, msg_prio, NULL);
}
/*path --glibc-2.18\rt\mq_timedsend.c*/
/* Add message pointed by MSG_PTR to message queue MQDES, stop blocking
   on full message queue if ABS_TIMEOUT expires.  */
int
mq_timedsend (mqd_t mqdes, const char *msg_ptr, size_t msg_len,
	      unsigned int msg_prio, const struct timespec *abs_timeout)
{
  __set_errno (ENOSYS);
  return -1;
}

#ifdef __NR_mq_notify
/* Register notification upon message arrival to an empty message queue
   MQDES.  */
int
mq_notify (mqd_t mqdes, const struct sigevent *notification)
{
  /* mq_notify which handles SIGEV_THREAD is included in the thread
     add-on.  */
  if (notification != NULL
      && notification->sigev_notify == SIGEV_THREAD)
    {
      __set_errno (ENOSYS);
      return -1;
    }
  return INLINE_SYSCALL (mq_notify, 2, mqdes, notification);
}

#else
# include <rt/mq_notify.c>
#endif

POSIX消息队列的实现

在Linux 2.6中,POSIX消息队列的实现是简单的。已经引入了一个叫做mqueue的特殊文件系统,每个现存队列在其中都有一个相应的索引节点。内核提供的系统调用mq_open()、mq_unlink()等,这些系统调用透明地对mqueue文件系统的文件进行操作,而大部分工作交由VFS层处理(linux提供了VFS,这让应用程序编程变得简单,因为应用程序不用去考虑不同文件系统的差异。)。

mqueue文件系统
/*可以通过如下命令查看是否挂载了明确月文件系统*/
root@ubuntu:/home# cat /proc/filesystems | grep mqueue
nodev	mqueue
其中第一列nodev表示该类型文件不需要挂载在一个块设备上,否则就需要挂在一个块设备上;
第二列表示当前系统中支持的文件系统类型。

Linux 常用的特殊文件系统功能说明

总结

通过对比学习了解到,POSIX 消息队列与System V IPC消息队列相比,具有更多优点。

参考

  1. 《深入理解LINUX内核》陈莉君 张琼声 张宏伟 译
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值