在多线程管道中维护订单

时间:2010-07-12 08:59:19

标签: multithreading

我正在考虑处理管道的多线程架构。我的主处理模块有一个输入队列,从中接收数据包。然后,它对这些数据包执行转换(解密等)并将它们放入输出队列。

线程来自于许多输入数据包可以使其内容彼此独立地转换。

然而,妙语是输出队列必须与输入队列具有相同的顺序(即,第一个拉出输入队列必须首先被推入输出队列,无论其转换是否先完成。)

当然,输出队列会有某种同步,所以我的问题是:确保维持这种排序的最佳方法是什么?

4 个答案:

答案 0 :(得分:11)

让一个线程读取输入队列,在输出队列上发布占位符,然后将项目交给工作线程进行处理。数据准备就绪后,工作线程会更新占位符。当需要输出队列中的值的线程读取占位符时,它可以阻塞,直到相关数据准备就绪。

因为只有一个线程读取输入队列,并且该线程立即将占位符放在输出队列中,所以输出队列中的顺序与输入中的顺序相同。工作线程可以很多,并且可以按任何顺序进行转换。

在支持期货的平台上,它们是占位符的理想选择。在其他系统上,您可以使用事件,监视器或条件变量。

答案 1 :(得分:4)

有以下假设

  • 应该有一个输入队列,一个输出队列和一个工作队列
  • 应该只有一个输入队列 听者
  • 输出消息应包含等待 句柄和指向工人/输出数据的指针
  • 可能有任意数量的 工人线程

我会考虑以下流程:

输入队列侦听器执行以下步骤:

  1. 提取输入消息;
  2. 创建输出消息:
    1. 初始化工作人员数据结构
    2. 重置等待句柄
  3. 将指向输出消息的指针排入 working 队列
  4. 将指向输出消息的指针排入输出队列
  5. 工作线程执行以下操作:

    1. 等待工作队列 提取指向输出的指针 来自它的消息
    2. 根据给定数据处理消息,并在完成后设置事件
    3. 消费者做了以下事情:

      1. 等待n 输出队列 提取指向输出的指针 来自它的消息
      2. 等待句柄直到输出数据准备好
      3. 对数据做了些什么

答案 2 :(得分:1)

这将是特定于实现的。一般的解决方案是对输入项进行编号并保留编号,以便稍后对输出项进行排序。这可以在填充输出队列时完成,或者可以作为填充输出队列的一部分来完成。换句话说,您可以将它们插入到正确的位置,只允许在下一个可用项目顺序时读取队列。

修改

我将草拟一个基本方案,试图通过使用适当的原语来保持简单:

  1. 我们不是将Packet排队到输入队列中,而是围绕它创建一个未来值,并将其排入输入和输出队列。在C#中,您可以这样写:

    var future = new Lazy<Packet>(delegate() { return Process(packet); }, LazyThreadSafetyMode.ExecutionAndPublication);
    
  2. 来自工作池的线程从输入队列中取出future并执行future.Value,这会导致委托运行JIT并在委托处理完数据包后返回。

  3. 一个或多个使用者从输出队列中将future出列。只要他们需要数据包的值,他们就会调用future.Value,如果工作线程已经调用了委托,则会立即返回。

  4. 简单,但有效。

答案 3 :(得分:0)

如果使用窗口方法(已知数量的元素),请使用数组作为输出队列。例如,如果是媒体流,则丢弃尚未足够快速处理的包。

否则,请使用priority queue(特殊类型的堆,通常基于固定大小的数组实现)作为输出项。

您需要添加序列号或任何可以将项目排序到每个数据包的数据。优先级队列是树状结构,可确保插入/弹出中的项目序列。