【问题标题】:Bottleneck in Threads C++线程 C++ 中的瓶颈
【发布时间】:2015-11-12 08:05:20
【问题描述】:

所以我只是想验证我的理解,希望你们能够消除任何误解。所以本质上我有两个线程使用相同的锁并在它们持有锁时执行计算,但有趣的是在锁内我会导致线程休眠一小段时间。对于两个线程,这个睡眠时间对于任何一个线程都会略有不同。由于锁的工作方式,较快的线程是否会被较慢的线程阻塞,因为它必须等待它完成?

例如:

Thread1() {

   lock();
   usleep(10)
   lock();

}

-

Thread2() {

   lock();
   sleep(100)
   lock();

}

现在因为 Thread2 持有锁的时间更长,这将导致瓶颈。只是为了确定,这个系统应该在谁获得锁上来回发生,对吧?

应该是:

Thread1 gets lock
Thread1 releases lock
Thread2 gets lock
Thread2 releases lock
Thread1 gets lock
Thread1 releases lock
Thread2 gets lock
Thread2 releases lock

等等,对吧? Thread1 应该永远无法在它释放后立即获取锁,不是吗?

【问题讨论】:

  • 锁锁?不锁解锁?
  • @GregorMcGregor 有没有办法防止这种情况发生?
  • 不建议让线程在持有锁的情况下休眠,并且出于您的目的(线程同步)休眠是错误的媒介。也许你应该使用一个额外的事件。线程 1 将等待该事件,该事件将在释放锁后从线程 2 发布。
  • sb9 已经说过了,但我想再次补充一点,您应该尽可能短地使用锁!
  • 这个问题和优先级倒置有什么关系?不涉及优先级。这只是互斥体(不存在)公平性的问题。另外,我怀疑这里使用睡眠只是为了模拟工作。

标签: c++ multithreading


【解决方案1】:

Thread1 应该永远无法在它释放后立即获取锁,不是吗?

,Thread1 可以在释放锁后立即重新获取锁,因为 Thread2 仍可能挂起(由于调度程序而处于休眠状态)

另外sleep 仅保证线程将至少睡眠所需的数量,它可以而且通常会更多。

实际上,在计算值时你不会持有锁,你会获得锁,获得计算所需的值,解锁,计算它,然后再次获得锁,检查计算的旧值是否仍然有效/想要,然后存储/返回您的计算结果。 为此,发明了 std::future 和 atomic 数据类型。

...这个系统应该在谁获得锁上来回发生,对吧?

大多数情况下大部分时间都是来回的,但有时线程 1 可能/将会有两个锁定/解锁周期。这取决于您的调度程序,任何执行和周期都可能会有所不同。

【讨论】:

  • 对这个例子严格来说,当 Thread2 处于休眠状态时,Thread1 无法重新获取锁,因为 Thread2 在锁定区域内休眠。只有调度程序才能使 Thread1 重新获取锁。
【解决方案2】:

绝对没有什么能阻止任何一个线程在释放锁后立即重新获得锁。我不知道你认为什么会阻止这种情况发生,但没有任何作用。

事实上,在许多实现中,已经运行的线程在获得对必须准备好运行的线程的锁定方面具有优势。这是最小化上下文切换的明智优化。

如果您使用睡眠作为模拟工作的一种方式,并认为这代表了锁公平性的一些现实问题,那您就错了。休眠的线程自愿放弃其时间片的剩余部分,并且其处理方式与耗尽其时间片工作的线程非常不同。如果这些线程真的在工作,最终一个线程会耗尽它的时间片。

【讨论】:

    【解决方案3】:

    根据您要达到的目标,有多种可能性。

    如果您希望线程以特定顺序运行,请查看here。 基本上有两种选择:
    - 一种是使用事件,其中一个线程发出信号通知下一个它已经完成了他的工作,因此下一个可以开始。
    - 另一种是有一个调度线程来处理事件或信号量的排序。

    如果您希望您的线程独立运行但有一个锁定机制,其中尝试获取锁定的顺序被保留,您可以查看here。答案的最后一部分使用每个线程一个条件变量的队列看起来不错。

    正如之前的答案和 cmets 所说,使用 sleep 进行调度是一个坏主意。 另外锁只是一种互斥机制,对执行顺序没有保证。 锁通常用于防止对关键资源的并发访问,因此它应该这样做。临界区越小越好。
    最后是的,尝试订购线程正在制造“瓶颈”。在这种特殊情况下,如果所有计算都在锁定部分进行,线程将不会并行执行任何操作,因此您可以质疑使用线程的实用性。

    编辑:
    只是更多警告:小心,线程不是因为在你的机器上工作(按你想的那样安排)10次,它总是会,特别是如果你改变任何上下文(机器,工作负载......)。您必须通过设计来确保它。

    【讨论】:

      猜你喜欢
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-03-24
      • 1970-01-01
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多