我正在考虑处理管道的多线程架构。我的主处理模块有一个输入队列,从中接收数据包。然后,它对这些数据包执行转换(解密等)并将它们放入输出队列。
线程来自于许多输入数据包可以使其内容彼此独立地转换。
然而,妙语是输出队列必须与输入队列具有相同的顺序(即,第一个拉出输入队列必须首先被推入输出队列,无论其转换是否先完成。)
当然,输出队列会有某种同步,所以我的问题是:确保维持这种排序的最佳方法是什么?
答案 0 :(得分:11)
让一个线程读取输入队列,在输出队列上发布占位符,然后将项目交给工作线程进行处理。数据准备就绪后,工作线程会更新占位符。当需要输出队列中的值的线程读取占位符时,它可以阻塞,直到相关数据准备就绪。
因为只有一个线程读取输入队列,并且该线程立即将占位符放在输出队列中,所以输出队列中的顺序与输入中的顺序相同。工作线程可以很多,并且可以按任何顺序进行转换。
在支持期货的平台上,它们是占位符的理想选择。在其他系统上,您可以使用事件,监视器或条件变量。
答案 1 :(得分:4)
有以下假设
我会考虑以下流程:
输入队列侦听器执行以下步骤:
工作线程执行以下操作:
消费者做了以下事情:
答案 2 :(得分:1)
这将是特定于实现的。一般的解决方案是对输入项进行编号并保留编号,以便稍后对输出项进行排序。这可以在填充输出队列时完成,或者可以作为填充输出队列的一部分来完成。换句话说,您可以将它们插入到正确的位置,只允许在下一个可用项目顺序时读取队列。
修改的
我将草拟一个基本方案,试图通过使用适当的原语来保持简单:
我们不是将Packet
排队到输入队列中,而是围绕它创建一个未来值,并将其排入输入和输出队列。在C#中,您可以这样写:
var future = new Lazy<Packet>(delegate() { return Process(packet); }, LazyThreadSafetyMode.ExecutionAndPublication);
来自工作池的线程从输入队列中取出future
并执行future.Value
,这会导致委托运行JIT并在委托处理完数据包后返回。
一个或多个使用者从输出队列中将future
出列。只要他们需要数据包的值,他们就会调用future.Value
,如果工作线程已经调用了委托,则会立即返回。
简单,但有效。
答案 3 :(得分:0)
如果使用窗口方法(已知数量的元素),请使用数组作为输出队列。例如,如果是媒体流,则丢弃尚未足够快速处理的包。
否则,请使用priority queue(特殊类型的堆,通常基于固定大小的数组实现)作为输出项。
您需要添加序列号或任何可以将项目排序到每个数据包的数据。优先级队列是树状结构,可确保插入/弹出中的项目序列。