【问题标题】:C++ random uniform_int_distribution return same values in all threadsC++ 随机 uniform_int_distribution 在所有线程中返回相同的值
【发布时间】:2020-06-01 22:23:32
【问题描述】:

我有以下代码,我需要在给定的间隔内有一个随机数。似乎按我的需要工作。

   std::default_random_engine eng;
     std::uniform_int_distribution<int> dist(3, 7);
     int timeout = dist(eng);

然后我在不同的线程中运行它并在循环中重复。

    std::default_random_engine defRandEng(std::this_thread::get_id());
    std::uniform_int_distribution<int> dist(3, 7);
    int timeout; // if I put timeout = dist(defRandEng); here it's all the same

    while (true)
    {
        timeout = dist(defRandEng);
        std::cout<<"Thread "<<std::this_thread::get_id()<<" timeout = "<<timeout<<std::endl;
        std::this_thread::sleep_for(std::chrono::seconds(timeout));
}

但是对于所有线程中的每次迭代,值都是相同的

Thread 139779167999744 timeout = 6
Thread 139779134428928 timeout = 6
Thread 139779067287296 timeout = 6
Thread 139779117643520 timeout = 6
Thread 139779100858112 timeout = 6
Thread 139779084072704 timeout = 6
Thread 139779151214336 timeout = 6
Thread 139779050501888 timeout = 6
Thread 139779033716480 timeout = 6

下一次互动

Thread 139779167999744 timeout = 4
Thread 139779151214336 timeout = 4
Thread 139779134428928 timeout = 4
Thread 139779117643520 timeout = 4
Thread 139779100858112 timeout = 4
Thread 139779084072704 timeout = 4
Thread 139779067287296 timeout = 4
Thread 139779050501888 timeout = 4
Thread 139779033716480 timeout = 4

【问题讨论】:

  • 它不是线程安全的......
  • 一个 C++ minimal reproducible example 有一个 main,所有需要的 #include 指令等。足够让其他人看到可以复制、粘贴和开始分析,所以每个人都可以看到其他细节这可能最终很重要。
  • minimal reproducible example 的真正魅力在于,如果不及时发现并解决问题,就很难做出一款出色的产品。当您删除不相关的代码时,该错误隐藏的空间就更少了,并且当您检查代码以确定它是否不相关时,检查可以摆脱问题。
  • 除了这是高度怀疑并且不应该发生的事实之外,您错误地为您的生成器播种。我不知道default_random_engine 是什么(因此它应该永远被使用)但是你可能没有给它足够的熵来播种它的整个内部状态,这会导致退化的结果(尽管如此,仍然不太可能在不同的种子中产生相同的序列)。我意识到这很难做到。不幸的是,C++ 随机数生成器很糟糕。

标签: c++ c++11 random


【解决方案1】:

您需要为随机引擎提供基于一些自然随机值的种子。下面的示例是从您的代码 sn-ps 中采用的,它适用于 3 个线程:

std::mutex lock;

void sample_time_out()
{
   std::stringstream ss;
   ss << std::this_thread::get_id();
   uint64_t thread_id = std::stoull(ss.str());

   std::default_random_engine eng(thread_id);
   std::uniform_int_distribution<int> dis(3, 7);


   for (int i = 0; i < 3; i++)
   {
      auto timeout = dis(eng);

      std::this_thread::sleep_for(std::chrono::seconds(timeout));
      {
         std::unique_lock<std::mutex> lock1(lock);
         std::cout << "Thread " << std::this_thread::get_id() << " timeout = " << timeout << std::endl;
      }
   }
}

int main()
{
   std::thread t1(sample_time_out);
   std::thread t2(sample_time_out);
   std::thread t3(sample_time_out);

   t1.join();
   t2.join();
   t3.join();

   return 0;
}

我第一次运行的输出是:

Thread 31420 timeout = 3
Thread 18616 timeout = 6
Thread 31556 timeout = 7
Thread 31420 timeout = 4
Thread 18616 timeout = 7
Thread 31420 timeout = 6
Thread 31556 timeout = 7
Thread 18616 timeout = 4
Thread 31556 timeout = 7

【讨论】:

  • 您对引擎的播种与 OP 的代码不同。
  • @Spencer 没错。如果没有提供种子,它每次都会生成相同的东西。顺便说一句,我更新了答案。谢谢。
  • 你尝试过像 OP 那样用std::this_thread::get_id() 播种吗?
  • @Spencer 实际上,std::this_thread::get_id() 不能直接传入随机引擎。我认为OP的代码不会编译。但是如果我将thread_id转换为unsigned int,然后用它初始化随机引擎,是的,它工作正常。
  • 我使用了std::hash&lt;std::thread::id&gt;,得到的结果与您的相似。
猜你喜欢
  • 1970-01-01
  • 2021-11-26
  • 2021-11-11
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多