我正在努力用一种正确的方法来初始化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]);
}
但是,这只会导致死锁。什么是解决这个问题的典型方法?我还考虑了一个互斥和条件变量来唤醒线程,但由于锁定,这可能是昂贵的,实际上只有在第一次调用函数时才需要。
答案 0 :(得分:1)
典型的方法是使用构造函数。
让Rng
的构造函数执行这些类型的初始化。
这实际上是它的工作。
不清楚为什么你首先在这里有static
数据。无论如何。
为什么不使用成员变量?