【问题标题】:How to multi-thread this?如何多线程这个?
【发布时间】:2011-02-23 11:59:03
【问题描述】:

我希望有两个线程。第一个thread1偶尔会调用如下伪函数:

void waitForThread2() {
  if (thread2 is not idle) {
    return;
  }
  notifyThread2IamReady(); // i.e. via 1st condition variable
  Wait for thread2 to finish exclusive access. // i.e. via 2nd condition variable.
}

第二个线程2永远在下面的伪循环中:

for (;;) {
  Notify thread1 I am idle.
  Wait for thread1 to be ready. // i.e. via 1st condition variable.
  Notify thread1 I am exclusive.
  Do some work while thread1 is blocked.
  Notify thread1 I am busy. // i.e. via 2nd condition variable.
  Do some work in parallel with thread1.
}

编写此代码的最佳方法是什么,以使线程 1 和线程 2 在具有多核的机器上尽可能保持忙碌。我想避免一个线程的通知和另一个线程的检测之间的长时间延迟。我尝试使用 pthread 条件变量,但发现线程 2 执行“通知线程 1 我很忙”与 thear2IsExclusive() 上的 waitForThread2() 中的循环之间的延迟可能长达近一秒。然后我尝试使用 volatile sig_atomic_t 共享变量来控制它,但是出了点问题,所以我一定没有正确地做。

【问题讨论】:

  • 你最好告诉人们你真正想要解决的问题,而不是要求他们实施你已经构想的解决方案......
  • 您的伪代码没有多大意义。你如何通知另一个你很忙的线程,为什么?此外,您在这里关注线程;通常,您需要同步数据。您正在同步哪些数据,您的并行操作如何?
  • 如果您的 condvars 需要一秒钟的时间来做任何事情,那么您就做错了。此外,规范的做法是锁定数据结构,而不是“通知另一个线程”;后者无法扩展。
  • @tc 大多数时候 cond var 很快,但有时可能需要接近一秒。
  • @WhirlWind 并行工作是在单独的数据上,因此不需要同步。目前,我通过条件变量通知我正忙的另一个线程。他们之所以通知是因为在短暂的忙碌期间,thread2正在修改thread1查看的数据结构。

标签: c++ pthreads mutex condition-variable


【解决方案1】:

似乎您应该使用信号量来发出信号,而不是让线程空闲的“while”循环等待某些条件发生。空闲循环很糟糕。

【讨论】:

  • 空闲循环实际上是为了解释这个想法,而不是真正以这种方式实现。我已将它们从问题中删除,因为它们会分散主要问题的注意力。目前,这些都是通过没有超时的条件变量实现的。
【解决方案2】:

在我看来,您正在尝试约会(来自 Ada 的术语)。

第二个线程正在等待第一个线程调用它,然后在第一个线程等待时立即执行一些工作,并在第一个线程完成后执行更多工作。

第一个线程正在“调用”第二个线程 - 如果第二个线程无法进行调用,则会立即超时。

Ada 直接在语言中支持这一点,但假设不能移植到 Ada...

这可以用三个信号量来实现。信号量 1 表示线程 1 已准备好会合。信号量 2 表示线程 2 已准备好会合。信号量 3 表示集合完成。

线程 1:获取信号量 1 的默认值。

 if Semaphore 2.acquire(timeout = 0) is successful # Thread 2 is ready
     Semaphore 1.release() # Indicate I am ready
     Semaphore 3.acquire() # Wait until the rendevous is complete.
     Semaphore 3.release()
     Semaphore 1.acquire() # Indicate I am not ready
     Semaphore 2.release() # I am no longer using thread 2.

 Do concurrent work 

线程 2:获取信号量 2 的默认值。

 Loop forever
     Semaphore 3.acquire() # Indicate Rendevous is not complete.
     Semaphore_2.release() # Indicate I am ready
     Semaphore_1.acquire() # Wait for Thread 1 to be ready
     Joint processing
     Semaphore 1.release() # I am no longer using thread 1.
     Semaphore 3.release() # Rendevous is complete.
     Semaphore 2.acquire() # I am not ready

 Post-processing

注意:从头开始编写,未经测试。看起来比我开始时想象的要复杂得多;我错过了什么吗?

【讨论】:

  • 信号量是否比使用带互斥锁的条件变量更有效?
  • 代码行效率更高?不知道。在运行时更高效?与所有其他间接费用相比,我怀疑你能分辨出区别。如果您的代码中没有太多更好的地方需要优化,我会感到非常惊讶。
【解决方案3】:

与其让您的线程互相告诉“我很忙”或“我不忙”,不如试着从您的线程正在操作的数据对象的角度来思考。

如果存在两个线程可能同时尝试更改的某些数据(例如计数器),则意味着您需要一个互斥体。

当一个线程对其他线程可能正在等待的共享数据状态进行更改时,向条件变量发出信号以通知它们。 (例如,如果生产者线程将数据添加到队列中,它可能会发出“dataAvailable”条件信号,消费者可能正在等待。)

【讨论】:

  • 我认为这是问题的核心。
猜你喜欢
  • 2011-12-29
  • 1970-01-01
  • 2016-12-22
  • 2011-12-26
  • 2022-01-23
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
  • 2019-12-10
相关资源
最近更新 更多