我正在努力寻找一种正确的方法来初始化 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]);
}
然而,这只会导致僵局。解决这个问题的典型方法是什么?我还考虑过使用互斥锁和条件变量来唤醒线程,但由于锁定,这可能代价高昂,实际上只在第一次调用函数时才需要。
最佳答案
典型的方法是使用构造函数。
让 Rng
的构造函数执行这些初始化。
这实际上就是它的工作。
不管怎样,你一开始就不清楚为什么这里有 static
数据。
为什么不使用成员变量?
关于C++多线程环境下静态变量的初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44244406/