【问题标题】:How can I cleanly mimic C++20 barrier behavior in C++14?如何在 C++14 中干净地模仿 C++20 的屏障行为?
【发布时间】:2021-07-07 04:36:12
【问题描述】:

C++20 引入了屏障,其中指定数量的线程必须通过调用到达与等待()到达屏障。一旦全部到达,就会从一个线程调用完成函数来重置屏障。然后所有线程都被释放,也许是为了迭代并再次遇到障碍。 在https://en.cppreference.com/w/cpp/thread/barrier 中找到了使用屏障的示例。 你将如何在 C++14 中干净地实现这个相同的示例? C++17 也很有趣,但我的限制实际上是 C++14。

请注意,我可以通过设置 /std:c++latest 在我的 VS 2019 中使用 C++20,但我还必须支持 VS 2015,我认为它不提供 std::barrier。

【问题讨论】:

  • 这听起来像是互斥锁、条件变量和计数器的简单组合。以简单的方式显着地可重新实现。忘记 C++17 或 C++14,这些基本块自 C++11 以来就存在。具体而言,您不清楚直接重新实现该算法的哪些方面?
  • @SamVarshavchik:嗯,barrier 在某些情况下是无锁的(如果所有线程都已到达,则需要立即进行任何wait 调用),因此基于互斥锁的实现是至少部分出局。实现起来并不像听起来那么简单。
  • 在站点文档中,您在哪里看到有关“无锁”的信息?仅仅因为在某些情况下没有等待并不意味着没有短暂获取和释放的锁。当谈到与进程间同步相关的讨论时,缺少“等待”并不意味着执行线程不会短暂地等待获取锁,如果该锁从未被任何进程长时间持有。
  • 由于您使用的是 MSVC,可能结帐:docs.microsoft.com/en-us/windows/win32/Sync/…
  • Boost 有barrier。可能不是最佳的,但作为后备足够好。或者类似this 之类的东西。

标签: c++ c++14


【解决方案1】:

示例代码只使用了arrive_and_wait和构造函数,加上完成函数。

struct Barrier {
  mutable std::mutex m;
  std::condition_variable cv;
  std::size_t size;
  std::ptrdiff_t remaining;
  std::ptrdiff_t phase = 0;
  std::function<void()> completion;
  Barrier( std::size_t s, std::function<void()> f ):
    size(s), remaining(s), completion(std::move(f))
  {}
  void arrive_and_wait()
  {
    auto l = std::unique_lock(m);
    --remaining;
    if (remaining != 0)
    {
      auto myphase = phase+1;
      cv.wait(l, [&]{
        return myphase - phase <= 0;
      });
    }
    else
    {
      completion();
      remaining = size;
      ++phase;
      cv.notify_all();
    }
  }
  void arrive_and_drop()
  {
      auto l = std::unique_lock(m);
      --size;
      --remaining;
      if (remaining == 0) {
          completion();
          remaining = size;
          ++phase;
          cv.notify_all();
      }
  }



};

或类似的东西。

【讨论】:

  • 谢谢。这个实现几乎是完美的。我只需要添加剩余的初始化。我还实现了arrive_and_drop()。谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 1970-01-01
  • 2020-11-17
  • 2018-07-20
相关资源
最近更新 更多