以下简单脚本并行生成随机数
#include <random>
#include <iostream>
#include <omp.h>
int main(int argc, char *argv[])
{
// Three integers are expected from the command line.
// The first integer is a random seed
// The second integer is the number of threads.
// The third integer indicates the number of random numbers to produce
// Read the seed and create the random number generator and the random distribution
int seed = std::stoi(argv[1]);
std::mt19937 mt(seed);
std::uniform_real_distribution<float> dist(0, 100);
// Read the number of threads and set it.
int nbThreads = std::stoi(argv[2]);
omp_set_num_threads(nbThreads);
// Number of random number for demonstration
int n = std::stoi(argv[3]);
// Will store the random number to print them conveniently
std::vector<float> store(n);
// produce 'n' random numbers
#pragma omp parallel for
for (int i = 0 ; i < n ; ++i)
{
store[i] = dist(mt);
}
// print the random numbers
for ( auto& rnd : store )
{
std::cout << rnd << std::endl;
}
return 0;
}
使用单个线程时,上述脚本是确定性的
./test 3 1 2
55.0798
7.07249
./test 3 1 2
55.0798
7.07249
./test 7 1 2
7.63083
22.7339
./test 7 1 2
7.63083
22.7339
然而,当使用多个线程时,它是部分随机的并且包含线程之间的相关性(这可能是一个非常大的问题)
./test 3 2 2
43.1925
43.1925
./test 3 2 2
55.0798
7.07249
./test 7 2 2
22.7339
7.63083
./test 7 2 2
7.63083
7.63083
我理解为什么我的代码不是线程安全的,但我不明白如何使其成为线程安全的。是否有可能具有确定性输出而不管线程数?
目标是./test 87 1 200
产生与./test 87 3 200
相同的输出(即线程数不会影响对象store
)。如果无法做到这一点,那么目标是./test 87 3 200
产生与./test 87 3 200
相同的输出。
答案 0 :(得分:1)
您正在std::mt19937
mt对象中与每个线程共享状态,这不是线程安全的。
使用某种类型的锁定来包装该对象的访问,或者为每个线程[EDIT]提供单独的实例(可能来自您创建的mt19937的第一个实例),以便每个实例提供不同的结果[/ EDIT ](如果有任何可能使用omp)。
答案 1 :(得分:0)
提供两个不同的mt19937实例(每个线程一个,以不同的方式播种)并不是最好的方法。在线程环境中有一个专用于RNG的库,您可以找到here。请务必阅读文档,写得非常好,特别是2.2节。