如果生产者线程在 numEmptySpaces 信号量上等待访问队列,这种行为可能无论如何都会发生,因为信号量等待队列在 FIFO 以外的任何地方实现是不合理的,但大多数情况下都不能保证信号量实现。
保证这种行为很尴尬,因为很难定义“线程顺序”的要求:
如何定义哪个线程先到达?
如果“第一个线程”获得某种类型的锁,阻止其他线程继续执行,那么后续线程“立即”聚集在其中,因此受操作系统提供的任何锁队列顺序的约束。
我唯一能想到的就是强制每个生产者线程在尝试锁定/排队任何东西之前获取一个无锁时间戳或序列号。这可以通过“正常”原子增量指令来完成。当生产者随后通过获取“numEmptySpaces”单元“进入”并锁定队列时,它可以按序列号顺序将自己排入队列。
我不确定是否可以为此使用标准的BlockingCollection。您可能可以按序列号对条目进行“排序”,但我不确定此操作是否会锁定队列 - 它应该这样做,但是.. 此外,必须将 sequenceNo 作为私有成员添加到 BlockingCollection后代和原子增量结果维护为每个任务的状态 - 您必须将其添加到 Task 成员。
我很想通过自己的 BlockingQueue 类构建一个“正常”队列、耦合信号量和互斥锁来实现这一点,一旦 numEmptySpaces 单元和队列互斥锁具有被收购。然后可以将原子增量结果组装到堆栈/自动变量中。
这可能是一个面试问题,但我必须受到解雇的威胁才能在生产代码中实际实现它。很难想到它可能是必要的情况。在我能想到的所有事情中,额外开销和争用的负面影响都超过了可疑的好处。
我对尝试在出队/执行端显式维护任何排序有类似的保留。尝试确保以序列号顺序到达出队任务中的某些“检查点”会很麻烦。它需要来自任务的合作,这需要一个私有同步对象成员在它到达其检查点时发出信号。永远不要尝试:)