2011-07-05 71 views
12

是std :: random_shuffle threadsafe?我认为不是因为正常的rand()不是线程安全的。如果是这样的话,我将如何使用rand_r和random_shuffle,这样我就可以给每个线程一个唯一的种子。我见过使用random_shuffle自定义随机生成器的例子,但对我而言仍然不清楚。是random_shuffle线程安全吗?并使用rand_r如果不是

谢谢。

+4

一般来说,你必须有这样的假设*不*在C++库线程安全,除非文档另有说明。 –

+1

另外,'threadsafe'是一个非常重载的术语。一些算法只有在对安全数据进行操作时才是安全的。只要只有一位作家,一些人可以安全地跨线程,而大多数人不能保证这一点。通常,在决定什么是安全(即正确)时,它要求您指定各种读/写要求。 – Kylotan

+0

只是为了澄清,我想在不同的列表上进行并行洗牌。所以我不关心数据结构中的种族,只是随机数的产生。 – Mark

回答

4

要与std::random_shuffle使用rand_r,你需要写一个(相当微不足道的)包装。您传递给random_shuffle的随机数生成器需要接受指定要生成的数字范围的参数,而rand_r则没有。

您的包装会是这个样子:

class rand_x { 
    unsigned int seed; 
public: 
    rand_x(int init) : seed(init) {} 

    int operator()(int limit) { 
     int divisor = RAND_MAX/(limit+1); 
     int retval; 

     do { 
      retval = rand_r(&seed)/divisor; 
     } while (retval > limit); 

     return retval; 
    }   
}; 

你会用它与random_shuffle类似:

std::random_shuffle(whatever.begin(), whatever.end(), rand_x(some_seed)); 
+0

谢谢。种子应该是一个unsigned int。另外,为什么会有while循环,而不是返回rand_r(&seed)%limit?我错过了一些微妙的东西吗? – Mark

+0

@Mark:糟糕 - 固定。关于do循环,考虑如何在3个孩子之间平均分配10颗糖果(并且你不能把一颗糖分成几块)。答案是你不能 - 你只能分发9个。这基本上是在'极限'儿童之间划分'RAND_MAX'糖果,并丢弃所有剩下的部分,这样所有的堆都是平等的。使用'%limit'(或'/ divisor')本身*不能*除非'RAND_MAX'恰好是'limit'的精确倍数(并且'RAND_MAX'通常是素数,所以它不是确切的倍数*任何*有意义的'极限')。 –

+0

虽然我同意杰里所说的一切,但有人可能会争辩说,如果你使用'rand_r',那么你就无权假定它有一个统一的分布来保存。但至少这样,*如果* rand_r是好的,那么你的洗牌也是好的,你不会引入任何新的偏见。 –

3

您需要提供一个随机数生成器函数或函数对象,它接受一个整型值类型并返回另一个不会溢出容器边界的整型类型的值,您已经传入函数的迭代器是迭代。同样在函数对象的情况下,它必须实现operator(),以便它可以像函数一样调用。因为你需要一个线程安全的随机数生成器,使用srandrandcstdlib是一个坏主意...你应该不是创建一个实现一个线程安全的随机数生成一些仿函数对象,或随机数发生器没有实现全局可访问的变量,因此一切都保持线程本地存储。

因此,例如,这种方法可行的一种方法是,您从另一个库中获得某种类型的随机数生成器,该生成器只会在固定值范围内生成随机值,以便您可以定义容器的边界对于random_shuffle算法使用的随机访问迭代器。现在,这取决于你用什么库,你仿函数可能类似于以下内容:

class my_rand_gen 
{ 
    private: 
     random_gen_type random_range_gen; 
     int min; 
     int max; 

    public: 
     my_rand_gen(const random_gen_type& gen, int min_range, int max_range): 
        random_range_gen(gen), min(min_range), max(max_range) {} 

     int operator()(int value) 
     { 
      //ignore the input value and use our own defined range 
      //returns a value between min and max 
      return random_range_gen(min, max); 
     } 
}; 

现在你可以调用算法,如:

random_shuffle(my_vector_start_iter, my_vector_end_iter, 
       my_rand_gen(rand_generator_lib, 
          vector_start_index, 
          vector_end_index)); 

,它会随机播放之间的矢量开始并将迭代器结束到您的向量中,而不会溢出向量的边界...换句话说,它将仅使用vector_start_indexvector_end_index之间的随机值。

+0

新的''类将是一个很好的开始 - 你可以有每个线程一个PRNG。 –

相关问题