线程局部静态uniform_int_distribution,是否会为不同的min,max组重新创建?

时间:2015-05-07 09:26:07

标签: c++ multithreading random thread-local-storage

this answer on stackoverflow(答案#2)@remyabel推荐这个模板:

#include <random>

std::mt19937& prng_engine()
{
  thread_local static std::random_device rd{};
  thread_local static std::mt19937 engine{rd()};

  // Or you can replace the two previous lines with:
  //thread_local static std::mt19937
  //  prng{std::random_device{}()};

  return engine;
}

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
    thread_local static std::uniform_int_distribution<T> dist{Min, Max};
    return dist(prng_engine());
}

只有dist只会创建一次,以便在线程中提供{T, Min, Max}套件吗?

如果我使用(1, 10)调用它,然后使用(11, 20)调用它,是否会重新创建?

2 个答案:

答案 0 :(得分:1)

因为它是静态的,所以dist只创建一次 - 第一次代码流过它。

第一次代码流过它时,Min和Max的值将是1和10.

在第二次调用时,不会重新创建dist,因此忽略Min和Max的新值,并获得1到10之间的随机数。

编辑:

这是getRandomNumberBetween的一个实现,可以满足您的需求:

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
    using range_t = std::pair<T, T>;
    using map_t = std::map<range_t, std::uniform_int_distribution<T>>;
    static thread_local map_t range_map;

    auto i = range_map.find(range_t(Min, Max));
    if (i == std::end(range_map))
    {
        i = range_map.emplace(std::make_pair(Min, Max), std::uniform_int_distribution<T> { Min, Max}).first;
    }
    return i->second(prng_engine());
}

答案 1 :(得分:1)

每个T只会创建一次(函数模板的每个实例都有自己的本地静态变量副本)。您可以查看:

std::cout << getRandomNumberBetween(0, 1) << '\n'
          << getRandomNumberBetween(10, 20) << '\n'
          << "------------------------\n"
          << getRandomNumberBetween('a', 'b') << '\n'
          << getRandomNumberBetween('c', 'z') << '\n';

由于分发对象是轻量级的,因此您可以在需要随机数时简单地构建新分布(例如Vary range of uniform_int_distribution):

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
  std::uniform_int_distribution<T> dist{Min, Max};
  return dist(prng_engine());
}

但您也可以考虑this implementation

template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
  using distribution_type = std::uniform_int_distribution<T>;
  using param_type = typename distribution_type::param_type;

  thread_local std::uniform_int_distribution<T> dist;
  return dist(prng_engine(), param_type(Min, Max));    
}