C ++在多线程环境中初始化静态变量

时间:2017-05-29 14:03:18

标签: c++ multithreading class static initialization

我正在努力用一种正确的方法来初始化C ++中的类的静态成员。上下文是随机数生成。我想要做的是为随机数生成创建一个类,并为每个线程创建一个引擎。

现在看起来像这样:

template<typename T, int MIN, int MAX>
class Rng {
 public:
  T operator()() {
    return get_random_number(omp_get_thread_num());
  }

 private:
  static T get_random_number(int id);
};

template<typename T, int MIN, int MAX>
T msl::Rng<T, MIN, MAX>::get_random_number(int id) {
  static std::vector<std::mt19937> engines;
  static std::vector<std::uniform_real_distribution<T>> dists;

  if (engines.empty()) { 
    int threads = omp_num_threads();
    engines.reserve(threads);
    dists.reserve(threads);

    for (int i = 0; i < threads; ++i) {
      std::random_device rd;
      std::mt19937 engine(rd());
      engines.push_back(engine);
      std::uniform_real_distribution<T> unif(MIN, MAX);
      dists.push_back(unif);
    }
  }

  return dists[id](engines[id]);
}

我这样用它:

int main(){

Rng<double, 0, 10> rng{};
auto init = rng();

int n = 100;
int a[n];

#pragma omp parallel for
  for(int i = 0; i < n; ++i){
    a[i] = rng();
  }
}

现在我想摆脱main方法中的前期初始化(auto init = rng()),但我不想引入不必要的开销,即线程不应该等待彼此等等,因为目前,初始化只进行了一次(很明显),但这一代发生了很多次。

我尝试的一件事是添加一个while循环,这样只有在第一次运行时所有线程都会等待master初始化引擎:

template<typename T, int MIN, int MAX>
T msl::Rng<T, MIN, MAX>::get_random_number(int id) {
  static std::vector<std::mt19937> engines;
  static std::vector<std::uniform_real_distribution<T>> dists;

  int threads = omp_num_threads();

#pragma omp master
{
  if (engines.empty()) { 
    engines.reserve(threads);
    dists.reserve(threads);

    for (int i = 0; i < threads; ++i) {
      // init stuff...
    }
  }
}

  while(engines.size() < threads)
    continue; 

  return dists[id](engines[id]);
}

但是,这只会导致死锁。什么是解决这个问题的典型方法?我还考虑了一个互斥和条件变量来唤醒线程,但由于锁定,这可能是昂贵的,实际上只有在第一次调用函数时才需要。

1 个答案:

答案 0 :(得分:1)

典型的方法是使用构造函数

Rng构造函数执行这些类型的初始化。

这实际上是它的工作。

不清楚为什么你首先在这里有static数据。无论如何。
为什么不使用成员变量