队列如何解决线程竞争问题?

How does a queue solve the thread race problem?

我看到有很多方法可以在处理多线程时避免竞争条件,但最常见的是互斥锁和队列。我不明白只要线程可能以混乱的顺序填充队列,队列如何使应用程序线程安全。

在并发系统中,(撇开线程优先级不谈),操作系统调度程序决定它在(多个)CPU 核心上接下来调度当前可运行的线程中的哪些。它试图做到“公平”,以免饿死一些不幸的线程,同时偏爱其他线程。在实时操作系统(例如 QNX)中,当然,还有更多细则,增加了这个简单的概念。

因此,在这样的系统中,不可能推断出“谁先来”,因为从应用程序的角度来看,调度程序的决定似乎是随机的(但公平)。

因此,如果有人试图创建一个“更好”的队列,他们可能会考虑使用优先级队列,并使用时间戳来对队列内容进行排序。但是 - 由于每个线程都获得一个时间戳(假设分辨率足够高),从应用程序的角度来看,它又是“随机的”,哪个线程先出现。

这 - 有点证明,队列与否 - 这个问题无法解决。

顺便一提,cpu 有 N 个中断源,它们的逻辑电平会同时改变。硬件优先级或处理这些中断的顺序取决于中断架构(每个中断的中断向量或带有软件调度的单个中断向量?),线路噪声,每个输入的电气特性的可变性等

如何解决这个问题?您不需要严格排序(x 在 y 之前),而是需要一些三元方法 (x, [y,z,t], u),其中 - 根据您的应用程序要求,您有一个“同时性”的概念。 IE。 x 首先出现,然后同时出现 y、z、t(在定义的时间间隔内),然后是 u。

此外,将您的线程以非循环有向图的形式排列,就像装配线上的小步骤而不是一些形成反馈循环的事件有助于避免“高阶”竞争条件。

就像在 www 中一样,对工作线程进行幂等请求也有帮助。 (a,b) -> ((a,b),c) 返回问题和答案是避免混淆的另一个技巧。

I cannot understand how a queue could make an application thread safe as long as the threads may populate the queue in a chaotic order.

首先,让我们摆脱“线程安全”。 “线程安全”实际上只应用于描述可用于构建应用程序的组件(函数、模块、类、库等)。

一个组件是 thread-safe 如果它保证在被多个线程同时使用时以某种有用且有据可查的方式运行。由于您在谈论队列,因此您可能对 thread-safe 队列有以下期望:

  1. 每个 put() 进入队列的项目最终都可以 take() 从队列中取出。
  2. 任何项目都不可能 take()en 不是 put()
  3. *IF* 程序将两个项目按一定的顺序放入队列,那么它们会take()en按相同的顺序,

但是,

  1. 如果程序允许并发 put() 调用队列,则队列无法保证这些项目实际出现在队列中的顺序。

“线程安全”并不真正适用于应用程序,因为应用程序的用户无法选择是以 multi-threaded 方式还是以 single-threaded 方式使用它。该选择是应用程序作者的baked-in。应用程序要么正确(按预期工作),要么不正确。

那么,让我们re-state回答您的问题:

I cannot understand how a queue could make an application correct as long as the threads may populate the queue in a chaotic order.

不能。如果应用程序依赖于对象 put() 以某种特定顺序进入队列,那么应用程序程序员有责任确保 put() 调用不重叠。如果允许调用重叠,则队列不可能知道应用程序程序员打算让项目进入队列的顺序。