2010-09-22 46 views
3

我试图编写一些能够快速计算随机数的东西,并且可以应用于多个线程。我当前的代码是:用于蒙特卡罗集成的线程安全随机数生成

/* Approximating PI using a Monte-Carlo method. */ 

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include <time.h> 
#include <omp.h> 
#define N 1000000000 /* As lareg as possible for increased accuracy */ 

double random_function(void); 

int main(void) 
{ 
    int i = 0; 
    double X, Y; 
    double count_inside_temp = 0.0, count_inside = 0.0; 
    unsigned int th_id = omp_get_thread_num(); 
    #pragma omp parallel private(i, X, Y) firstprivate(count_inside_temp) 
    { 
     srand(th_id); 
     #pragma omp for schedule(static) 
     for (i = 0; i <= N; i++) { 
     X = 2.0 * random_function() - 1.0; 
     Y = 2.0 * random_function() - 1.0; 
     if ((X * X) + (Y * Y) < 1.0) { 
     count_inside_temp += 1.0; 
    } 
    } 
    #pragma omp atomic 
     count_inside += count_inside_temp; 
    } 
    printf("Approximation to PI is = %.10lf\n", (count_inside * 4.0)/ N); 
    return 0; 
} 

double random_function(void) 
{ 
    return ((double) rand()/(double) RAND_MAX); 
} 

这工作,但通过观察我知道它不是使用的所有线程的资源管理器。 rand()是否适用于多线程代码?如果不是,有没有一个好的选择?非常感谢。 Jack

回答

7

rand()线程安全吗?也许,也许不是:

The rand() function need not be reentrant. A function that is not required to be reentrant is not required to be thread-safe."

一个测试和良好的学习锻炼将替换,比如调用rand(),固定整数看看会发生什么。

我想到的伪随机数发生器的方式是作为一个黑盒子,它将一个整数作为输入并返回一个整数作为输出。对于任何给定的输入,输出总是相同的,但数字序列中没有模式,并且序列均匀分布在可能输出的范围内。 (这个模型不完全准确,但它会做。)你使用这个黑盒子的方式是选择一个凝视的数字(种子)在你的应用程序中使用输出值,并作为下一次调用随机数发生器。有两种常用的方法来设计API:

  1. 两个函数,一个设置初始种子(例如srand(seed))和一个来检索序列(例如rand())的下一个值。 PRNG的状态在内部存储在某种全局变量中。生成一个新的随机数不会是线程安全的(很难说,但输出流将不可重现),或者在多线程代码中会很慢(最终会在状态值周围出现一些序列化)。
  2. PRNG状态暴露给应用程序员的接口。这里通常有三个函数:init_prng(seed),它返回PRNG状态的一些不透明表示,get_prng(state),它返回一个随机数并更改状态变量,以及destroy_peng(state),它只是清理分配的内存等等。这种类型的API的PRNG都应该是线程安全的且平行于无锁定运行(因为你是负责管理(现在是线程本地)状态变量。

我一般写在Fortran和使用Ladd's实施Mersenne Twister PRNG(该链接值得一读)C中有许多合适的PRNG,它将状态暴露给你的控制PRNG看起来不错,并且使用它(在并行区域和私有状态变量内初始化并销毁调用)应该给你一个体面的加速。

最后,通常情况下,PRNGs可以做得更好,如果你一次要求一个随机数的整个序列(e 。G。编译器可以矢量化PRNG内部)。由于这个库通常有类似get_prng_array(state)的函数,它们会返回一个包含随机数字的数组,因为如果将get_prng放在填充数组元素的循环中 - 它们只会更快地执行。这将是第二次优化(并且需要在并行for循环中添加一个for循环)显然,您不希望这样做的每线程堆栈空间用完!

+0

Ladd's实现的链接已经死机,有关fortran实现的其他建议? – lalmei 2014-09-05 11:03:59