【问题标题】:How to generate random numbers in a thread safe way with OpenMP如何使用 OpenMP 以线程安全的方式生成随机数
【发布时间】:2016-05-18 16:19:21
【问题描述】:

在并行化之前,我在循环外创建了一个default_random_engine 对象,因为创建这样的对象并不便宜。我在循环中重用它。

当与OpenMP 并行化时,我注意到uniform_dist(engine) 对随机引擎进行了可变引用,我认为它不是线程安全的。 程序没有崩溃,但我担心它的正确性。

我假设random_device 是线程安全的,所以我可以在循环内移动default_random_engine 的定义,但我不想每次迭代都创建一个随机引擎对象,因为我读到这并不便宜。

我认为另一种方法是创建default_random_engine 对象的数组(大小:线程数),并使用 OpenMP 函数在每次迭代开始时根据线程 ID 选择正确的对象。

有没有更好的办法?

#include <iostream>
#include <random>
using namespace std;

int main() {
    int N = 1000;
    vector<int> v(N);
    random_device r;
    default_random_engine engine(r());

    #pragma omp parallel for
    for (int i = 0; i < N; ++i) {
         uniform_int_distribution<int> uniform_dist(1, 100);
         // Perform heavy calculations
         v[i] = uniform_dist(engine); // I assume this is thread unsafe
    }
    return 0;
}

【问题讨论】:

标签: c++ multithreading random openmp


【解决方案1】:

由于实际代码将随机引擎传递给许多函数(每个函数都从不同的分布中生成整数和实数),因此我选择了每个线程的生成器数组,因为它对代码库的更改最少:

#include <iostream>
#include <omp.h>
#include <vector>
#include <random>
using namespace std;

int main() {
    random_device r;
    std::vector<std::default_random_engine> generators;
    for (int i = 0, N = omp_get_max_threads(); i < N; ++i) {
        generators.emplace_back(default_random_engine(r()));
    }

    int N = 1000;
    vector<int> v(N);

    #pragma omp parallel for
    for (int i = 0; i < N; ++i) {
        // Get the generator based on thread id
        default_random_engine& engine = generators[omp_get_thread_num()];
        // Perform heavy calculations
        uniform_int_distribution<int> uniform_dist(1, 100);
        v[i] = uniform_dist(engine); // I assume this is thread unsafe
    }
    return 0;
}

请记住,此代码假定函数omp_set_num_threads 永远不会在程序中被调用。如果发生这种情况,线程可能会获得比旧的 omp_get_max_threads() 更大的数字 (omp_get_thread_num()),这将导致缓冲区溢出错误。

遗憾的是,此解决方案采用标准 as explained in this other comment 不需要的实现细节。

【讨论】:

    猜你喜欢
    • 2017-04-20
    • 2020-01-31
    • 1970-01-01
    • 2014-10-16
    • 2012-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多