等待多个信号量或多个消息队列
Waiting on multiple semaphores or multiple message queues
In most implementations of UNIX, processes can block on more than one event. That is, rather than waiting on a single semaphore or receiving from a single message queue, the process can wait on multiple semaphores or multiple message queues. What advantage does such a capability offer? How would you implement this?
现在,在每个人开始问这是不是我的作业之前,不是。这是我正在参加的 class 的推荐考试题目。
我对此的看法 - 是这样的:
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
),则永远不会处理低优先级队列中的消息。
Is there a better way to handle this?
是的。主要问题是您的代码不断浪费 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() 正是这样做的。 google 的良好关键字包括 "select"、"multiplexing" 和 "non-blocking I/O"。
当使用不同的优先级消息队列时,reader 将继续为高优先级队列提供服务,当用完时,它将移至低优先级队列。如果不使用优先级,可以使用线程并行服务队列,但不能保证消息在不同队列中出现的顺序。
In most implementations of UNIX, processes can block on more than one event. That is, rather than waiting on a single semaphore or receiving from a single message queue, the process can wait on multiple semaphores or multiple message queues. What advantage does such a capability offer? How would you implement this?
现在,在每个人开始问这是不是我的作业之前,不是。这是我正在参加的 class 的推荐考试题目。
我对此的看法 - 是这样的:
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
),则永远不会处理低优先级队列中的消息。
Is there a better way to handle this?
是的。主要问题是您的代码不断浪费 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() 正是这样做的。 google 的良好关键字包括 "select"、"multiplexing" 和 "non-blocking I/O"。
当使用不同的优先级消息队列时,reader 将继续为高优先级队列提供服务,当用完时,它将移至低优先级队列。如果不使用优先级,可以使用线程并行服务队列,但不能保证消息在不同队列中出现的顺序。