工作线程,具有特定 "colour" 的作业,每种颜色只能有一个作业 运行,我需要什么同步原语?

Worker threads, jobs which have a particular "colour", only one job of each colour must be running, what synchronization primitive do I need?

我有 N 个工作线程和一个作业队列。当工作线程空闲时,它会从队列中选择一个作业并开始 运行ning 它。到目前为止,很简单。

但是我的工作有一个 属性,我称之为 "colour"。两个相同颜色的作业绝不能同时 运行ning。

例如,假设有 2 个线程,一个正在 运行ning 红色作业,另一个空闲。空闲线程查看队列,但它不能选择红色作业(因为如果它这样做,将有两个红色作业 运行ning,这是不允许的)。例如,如果队列中有一个蓝色作业,它可以 运行 它。如果队列中只有红色作业,则空闲线程必须等待另一个线程完成。然后两个线程都空闲,它们必须选择不同颜色的作业到 运行,如果到那时队列中仍然只有红色作业,则必须保持空闲状态。

我的问题是我应该在这里使用什么同步原语。我考虑过将队列分组为颜色,并且可以为每个颜色组附加一个互斥锁,但后来我陷入了如何使用这些互斥锁的困境。 (实际程序是使用 pthreads 在 OCaml 中编写的,因此它可以访问通常的 pthread 原语和构建在 pthreads 之上的原语)。

这听起来像是一个相当不寻常的案例,但它与现实世界的问题有关:我正在编写一个依赖项 运行ner(想想:"make")。如果两个配方都针对相同的输出文件 ("colour"),则绝不能 运行 两个配方 ("jobs") 并行。

有几个 "obvious" 解决方案。

  1. 您可以有一个 "red" 线程和一个 "blue" 线程,分别为 "red" 和 "blue" 队列提供服务。由于您永远不希望有一个以上的 "red" 作业在进行,因此拥有一个线程池不会给您带来任何好处。

  2. 如果出于某种原因您仍想在线程池上多路复用 "red" 作业,您仍然可以使用单独的 "red" 和 "blue" 队列,以及指示相应颜色作业是否正在进行的布尔标志。然后空闲线程将遍历所有非空队列并选择第一个具有 in_progress == false.

  3. 的队列
  4. 您可以将一个队列与一组布尔标志组合在一起。现在空闲线程将遍历队列,直到找到 in_progress[color] == false 的作业并选择它。

My question is what synchronization primitives I should use here.

您可以使用多种同步对象来保护队列和任何其他共享对象免受数据争用。互斥量和信号量在其中很突出,但也有其他的。

但是,由于其中一种可能性是线程必须挂起操作直到满足条件(新颜色的任务可用或任务完成),因此您需要一个条件变量。条件变量必须与互斥量一起使用,自然的习惯用法是互斥量保护(至少)必须访问以评估条件的共享数据。因此,"one mutex and one condition variable" 是对所提出问题的一个很好的回答。

但是您似乎还不确定如何构建队列以及如何使用同步原语。这是特定于您的特定项目的,但可以提出一些一般性的意见和建议。您对现实世界案例的解释表明,颜色值本质上是任意的,而不是从一个小的、固定的词汇表中得出。这排除了为每种颜色指定一个单独的线程,而是让您处于这样一种情况:在任何给定时间,每个空闲线程都可以用于 运行 符合 运行.[=12 条件的每个任务=]

从示意图上看,每个工作线程都会做这样的事情:

  1. 锁定互斥量
  2. 如果没有入队任务符合运行的条件,则

    一个。 等待条件变量

    b。当线程returns退出wait,回到(2).

  3. (如果控制到达这一点,则队列中有一个合格的任务。)出列一个合格的任务,T,颜色为C(T).

  4. 更新颜色跟踪数据以显示颜色 C(T) 的任务是 运行ning。
  5. 解锁互斥体
  6. 运行任务T.
  7. 锁定互斥量
  8. 更新颜色跟踪数据以显示不再有颜色任务 C(T) 运行宁.
  9. 广播到条件变量.
  10. 返回 (2)。

我想您会想要包含一个终止条件以允许您的线程干净地退出。这可能会作为步骤 (2) 的一部分进行评估。确保在跳出循环后,线程 解锁互斥量 .

另请注意,当工作线程 运行ning 时想要将新任务加入队列的线程——无论是工作线程本身还是其他线程——必须在这样做时持有互斥锁,并且应该广播这样做之后到简历。

I thought about grouping the queue into colours, and I can attach a mutex to each colour group, but then I'm stuck on how to use those mutexes.

确实如此。每组一个互斥量没有帮助,因为只有一个互斥量可以与 CV 相关联。当一个线程正在评估是否满足继续进行的条件时,以及当一个线程正在更新评估该条件所涉及的任何数据时,必须持有该互斥体。保护该数据子集的额外互斥量将无济于事,因为永远不会有超过一个线程争用它们(持有主互斥量的线程)。

向您的队列添加结构以方便评估哪些任务有资格 运行 可能仍然是合理的,但您没有给我们足够的信息来建议细节。 (而且这个问题已经很广泛了,所以请不要用任何此类信息来扩展它。)