2017-02-10 422 views
13

我有一些代码,看起来有点像这样:线程安全:: random_device

std::random_device rd; 

#pragma omp parallel 
{ 
    std::mt19937 gen(rd()); 
    #pragma omp for 
    for(int i=0; i < N; i++) 
    { 
     /* Do stuff with random numbers from gen() */ 
    } 
} 

我有几个问题:

  • std::random_device线程安全的?即当多个线程同时调用它时,它会做些什么没有帮助的事情?
  • 这通常是一个好主意吗?我应该担心重叠的随机数字流吗?
  • 有没有更好的方法来实现我想要的(每个线程中独立的随机数字流 - 我现在不担心重复性)?

如果它做出我主要在Windows上运行的std::random_device运作有什么区别,不过我想代码在Linux和OSX同样出色的工作为好。

+0

您可以实现再现性,但使用特定的种子而不是使用'std :: random_device'。 – Galik

+0

'random_device'很可能被阻塞。如果你想要的是并行性,那么使用它就没有多少意义。你可以使用一个用'random_device'播种的全局PRNG来播种'mt19937'(但它需要明确的锁定)。 – sbabbi

回答

3

注:这个答案适用于一般GCC LinuxOpenMP不能保证与std线程模型互操作,使功能,如thread_local可能无法正常工作。

(会删除这个答案,如果它会让我)

我可能会做出PRNG线程局部静态与初始化一个临时std::random_device

#pragma omp parallel 
{ 
    // different gen for each thread 
    thread_local static std::mt19937 gen(std::random_device{}()); 
    #pragma omp for 
    for(int i=0; i < N; i++) 
    { 
     /* Do stuff with random numbers from gen() */ 
    } 
} 

这会给你只有一个std::mt19937每个线程并通过多次调用函数来构建它们可节省时间。

+1

谢谢,我不知道'thread_local'关键字。更一般地说,当使用openmp并行区域来做这种事情时,我应该使用'thread_local'来正确地将线程变成本地的吗?我想只是声明并行区域内的变量就足够了? – Theolodus

+0

@Theolodus其实是的,你是对的,在一个平行区域使它已经具有特定的线程。我想从这里得到的结论是,线程特定意味着如果经常调用该函数,可以使其成为“静态”,从而提供潜在的性能提升,并且可以暂时初始化该生成器而无需花费构建临时的多次(每线程) – Galik

+0

你确定'#pragma omp'完全服从C++ 11线程模型吗?线程本地程序保证在'std'线程中工作,但是为了让它们在其他线程系统中工作,您需要该线程系统的编写者的保证...... – Yakk