【问题标题】:How to make threads with std::execution::par_unseq thread-safe?如何使带有 std::execution::par_unseq 线程安全的线程?
【发布时间】:2021-11-18 20:03:29
【问题描述】:

我正在阅读 C++ 并发操作。 它说当你使用 std::execution::par 时,你可以使用每个内部元素的互斥锁,如下所示。

#include <mutex>
#include <vector>

class X {
  mutable std::mutex m;
  int data;

 public:
  X() : data(0) {}
  int get_value() const {
    std::lock_guard guard(m);
    return data;
  }
  void increment() {
    std::lock_guard guard(m);
    ++data;
  }
};

void increment_all(std::vector<X>& v) {
  std::for_each(v.begin(), v.end(), [](X& x) { x.increment(); });
}

但是它说当你使用 std::execution::par_unseq 时,你必须用下面这样的整个容器互斥体替换这个互斥体

#include <mutex>
#include <vector>

class Y {
  int data;

 public:
  Y() : data(0) {}
  int get_value() const { return data; }
  void increment() { ++data; }
};

class ProtectedY {
  std::mutex m;
  std::vector<Y> v;

 public:
  void lock() { m.lock(); }
  void unlock() { m.unlock(); }

  std::vector<Y>& get_vec() { return v; }
};

void incremental_all(ProtectedY& data) {
  std::lock_guard<ProtectedY> guard(data);
  auto& v = data.get_vec();
  std::for_each(std::execution::par_unseq, v.begin(), v.end(),
                [](Y& y) { y.increment(); });
}

但是即使你使用第二个版本,并行算法线程中的 y.increament() 也存在数据竞争条件,因为并行算法线程之间没有锁。

带有 std::execution::par_unseq 的第二个版本如何是线程安全的?

【问题讨论】:

    标签: c++ concurrency c++17 mutex parallel.foreach


    【解决方案1】:

    它只是线程安全的,因为您不会在并行算法中访问共享数据。

    唯一并行执行的是对y.increment() 的调用。这些可以以任何顺序发生在任何线程上,并且可以任意相互交错,即使在单个线程中也是如此。但是y.increment() 只访问y 的私​​有数据,并且每个y 都与所有其他向量元素不同。所以这里没有数据竞争的机会,因为各个元素之间没有“重叠”。

    如果increment 函数还访问某个在向量的所有不同元素之间共享的全局状态,则另一个示例是。在这种情况下,现在有可能发生数据竞争,因此需要同步对共享全局状态的访问。但是由于并行无序策略的具体要求,这里不能只使用互斥锁进行同步。

    请注意,如果在并行算法的上下文中使用互斥锁,它可以防止不同的危害:一种用途是使用互斥锁在执行 for-each 的不同线程之间进行同步。这适用于并行执行策略,但 用于并行未排序。这不是您的示例中的用例,因为在您的情况下没有共享数据,因此我们不需要任何同步。相反,在您的示例中,互斥锁仅将 for-each 的调用与可能仍作为更大应用程序的一部分运行的任何 other 线程同步,但在 for-each 本身内没有同步。这对于并行和并行未排序都是一个有效的用例,但在后一种情况下,它不能通过使用每个元素的互斥体来实现。

    【讨论】:

      猜你喜欢
      • 2012-03-07
      • 1970-01-01
      • 2013-02-10
      • 2013-01-07
      • 1970-01-01
      • 2019-06-07
      • 2017-04-30
      相关资源
      最近更新 更多