310

问答题 310 /393

请你说一说消息队列、信号量的实现方式

参考答案

参考回答:

消息队列是消息的链接表,存储在内核中,由消息队列ID来标识。每个队列都有一个msgid_ds结构与其相关联:
struct msgid_ds
{
struct ipc_perm msg_perm;
msgqnum_t msg_qnum; /* # of messages on queue */
msglen_t msg_qbytes; /* max # of bytes on queue */
pid_t msg_lspid; /* pid of last msgsnd() */
pid_t msg_lrpid; /* pid of last msgrcv() */
time_t msg_stime; /* last-msgsnd() time */
time_t msg_rtime; /* last-msgrcv() time */
time_t msg_ctime; /* last-change time */
...
};

此结构定义了队列的当前状态。msgget用于创建一个新队列或打开一个现有队列,msgsnd将消息添加到队列的尾端(每个消息包括一个长整型类型字段,一个非负的长度,实际的数据长度),msgrcv用于从队列中取消息(并不一定要以先进先出次序取消息,可以按消息的类型字段取消息)。


信号量是一个计数器,用于为多个进程提供对共享对象的访问。为了正确地实现信号量,信号量的测试及加减1操作应当是原子操作,为此,信号量通常是在内核中实现的。

常用的信号形式是二元信号量(binary semaphore)。它控制单个资源,其初始值为1。但是,一般而言,信号量的初值也可以是任意一个正值,表明有多少个共享单位可供共享。

内核为每个信号量集合维护着一个semid_ds结构:

struct semid_ds
{
struct ipc_perm sem_perm;
unsigned short sem_nsems; /* # of semaphores in set */
time_t sem_otime; /* last-semop() time */
time_t sem_ctime; /* last-change time */
...
};

每个信号量由一个无名结构体表示,至少包含下列成员:

struct
{
unsigned short semval; /* semaphore value, always >= 0 */
pid_t sempid; /* pid for last operation */
unsigned short semncnt; /* # processes awaiting semval > curval */
unsigned short semzcnt; /* # processes awaiting semval == 0 */
...
};