c-等待多个信号量或多个消息队列



在大多数UNIX实现中,进程可以阻塞多个事件。也就是说,进程可以等待多个信号量或多个消息队列,而不是等待单个信号量或从单个消息队列接收。这样的能力有什么优势?你将如何实现这一点?

现在,在每个人开始问这是否是我的学校作业之前,它不是。这是我正在参加的一门课的推荐考试题。

我的想法是这样的:

typedef struct QueueElement {
int Sender;
int Receiver;
char Message[MAX_MSG_SIZE];
int MessageSize;
} QueueElement;
QueueElement MessageQueue[NUM_OF_PROCESSES];

/* Send Message to receiving process queue number */
int SendMsg(int SenderId, int ReceiverId, char* Msg, int Size)
{
/* Create Queue Element to Enqueue */
QueueElement El = {
.Sender = SenderId,
.Receiver = ...
.
.
};
/* Enqueue element in queue specified by Receiver's Id */
Enqueue(&(MessageQueue[ReceiverId]), El);
}

/* Get messages for process defined by ReceiverId, from any queue */
int RecvMsg(int* SenderId, int ReceiverId, char* Msg, int* size)
{
int i;
for (i=NUM_OF_PROCESSES; i>=0; i--)
{
/* If a message is available for receiving process, Dequeue element from queue */
if (MessageQueue[i].Receiver = ReceiverId)
{
QueueElement El = Dequeue(&(MessageQueue[i]));
*SenderId = El.Sender;
strcpy(Msg, El.Message);
.
.
.
return TRUE;
}
}
return FALSE;
}

现在,考虑4个并行运行的进程。它们不断地向消息队列1、2、3、4发送消息。现在,假设所有消息都被发送到进程2。这意味着进程2必须检查所有4个队列(1、2、3、4(中的消息。但是,如果不断添加新消息,则只有队列4中的消息才会得到处理。如何避免让其他消息队列挨饿?

有更好的方法来处理这个问题吗?现代建筑是如何处理这一问题的?此解决方案的问题是,如果消息继续进入高优先级队列(NUM_OF_PROCESSES(,则低优先级队列中的消息将永远不会得到处理。

有更好的方法来处理这个问题吗?

是。主要的问题是,您的代码不断地浪费CPU时间进行轮询,因为它根本不等待。

更好的方法是把它放在内核中,这样:

  • 当任务调用RecvMsg()时,内核可以原子化地(无竞争条件(执行if no messages in queue { tell scheduler this task should block until a message is received }

  • 当任何东西调用SendMsg()时,内核可以原子地(无竞争条件(执行if receiving task is blocked waiting for a message { tell scheduler the receiving task should be unblocked }

下一个问题是它只等待消息。如果您想等待文件(异步(打开,或者等待信号,或者等待时间流逝,或者等待获取互斥,该怎么办?对于这个问题,有两种可能的解决方案:

  • 有一个可怕的混乱(例如epoll_pwait()(,不同类型的东西有不同的参数(仍然不能用于某些事情,例如等待互斥(。

  • 实现消息之上的所有内容,这样您就只需要等待消息。

对于第二个解决方案;您最终大多会用actor模型取代传统的过程式编程。

我认为您的代码没有按照询问者的意图回答问题。扩展问题的内容:

通常情况下,你可以调用类似read()的东西从文件描述符中读取,它会阻止直到一些数据进入。但是,如果你有多个文件描述符,并且你想同时阻止所有文件描述符,直到数据进入其中任何一个,该怎么办?使用一个只使用单个文件描述符的简单read()是无法做到这一点的。

  • 您需要什么样的API?显示一个函数或一组函数,使某人可以同时从多个源读取

提示:select((正是这样做的。谷歌上的好关键词包括"选择"、"多路复用"one_answers"非阻塞I/O"。

当使用不同优先级的消息队列时,读取器将继续为高优先级队列提供服务,当高优先级队列用完时,它将移动到低优先级队列。在不使用优先级的情况下,线程可以用于并行为队列提供服务,但它不能保证消息在不同队列上出现的顺序。

最新更新