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 模型替换传统的过程式编程。
推荐阅读
- javascript - 如何使这个 JavaScript 脚本与所有浏览器交叉兼容?
- javascript - 如何停止节点 js-winston 库中出现的 audit.json 文件
- python - 在 Skikit Learn 中为用户输入获取错误的标签编码
- c++ - 写入新值是预增量表达式“值计算”的一部分,还是“副作用”?
- ffmpeg - ffmpeg 将 cdg/mp3 转换为 mp4 但 cdg 曲目总是加快一秒
- android - 如何解决“指定的孩子已经有父母。您必须先在孩子的父母上调用 removeView()。”?
- fluent-assertions - 集合比较中不匹配项的流利断言消息
- reactjs - 使用 Formik 进行 React-select 不会更新选择字段,但会执行其他所有操作
- swiftui - SwiftUI contextMenu 不刷新
- git - 如何阻止 git 跟踪文件夹?