【问题标题】:Threads, how to seed random number generator independently?线程,如何独立播种随机数生成器?
【发布时间】:2016-04-22 20:05:54
【问题描述】:

我昨天在这里问了一个关于线程和获取输入以创建用户指定的线程数量的问题。在你的帮助下,我能够弄清楚。除了这一次,我正在处理同一个程序,我需要帮助来让程序中的每个线程独立地为随机数生成器提供种子。如果这听起来很简单,我很抱歉。我还是个线程新手。

基本上我的程序正在做的是询问用户他们想要创建多少线程,以及他们想要抛出多少箭头。每个箭头将生成 2 个数字,从 -1 到 1。这是我目前的程序。它是工作代码,因此您可以在需要时运行它:

#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>
#include <thread>

using namespace std;

void exec(int n, int randNumbers)
{
    int seed = 0;

    srand(seed);
    int random_number = rand() % 1 + -1;

    cout << "Thread " << n << endl;
    cout << "\n";

    while (randNumbers != 0)
    {
        srand(seed);
        cout << random_number << endl;
        seed++;
        cout << "Seed: " << seed << endl;
        cout << "\n";

        cout << random_number << endl;
        seed++;
        cout << "Seed: " << seed << endl;
        cout << "\n";
        randNumbers--;
    }
}


int main()
{
    int numThreads = 0; // Threads
    int maxRandom; // Arrows

    cout << "This is a Monte Carlo simulation." << endl;
    cout << "Please enter the number of threads to run." << endl;
    cout << "Threads: ";

    cin >> numThreads;

    // create an array of threads
    thread* myThreads = new thread[numThreads];

    if ((numThreads > 20) || (numThreads < 1))
    {
        cout << "Sorry. Something went wrong." << endl;
        return 0;
    }

    system("CLS");
    cout << "\n";
    cout << "Enter the number of arrows you would like to throw: " << endl;
    cout << "Arrows: ";

    cin >> maxRandom; // Arrows

    system("CLS");
    for (int i = 0; i < numThreads; i++)
    {
        // run random number generator for thread at [i]
        myThreads[i] = thread(exec, i, maxRandom);
    }

    for (int i = 0; i < numThreads; i++)
    {
        myThreads[i].join();
    }

    cout << "Done!" << endl;
}

无论int seed 是否增加 1,所有线程都返回 -1。我已经查看了所有内容,但我似乎仍然无法弄清楚为什么我的线程没有独立地播种随机数生成器。有谁知道发生了什么?我对线程还是陌生的。任何帮助将不胜感激。非常感谢。

【问题讨论】:

  • 停止使用rand,并在每个线程中创建一个random number generator
  • 为什么需要不同的线程来独立地为 RNG 播种?它只需要播种一次,您可以并且应该在启动任何其他线程之前执行此操作。请记住srand()rand() 不是线程安全的——您必须序列化对它们的访问。
  • 不要在线程中播种你的生成器。在开始任何线程之前播种它。您与 rand() 和 srand() 一起使用的生成器对于整个程序来说是独一无二的。另一个问题是rand 不是线程安全的。
  • 另外,您可能应该在执行srand() 之后立即放弃对rand() 的第一次调用,然后进入线程。 Windows 有一个错误(或至少有),在序列的开头不是很随机。
  • 正如 John 所说,srand()rand() 不是线程安全的。如果您的应用程序在 intel cpu 上运行,intel DRNG library 将是一个不错的选择,因为它利用了确保加密安全的rdrand CPU 指令

标签: c++ multithreading random


【解决方案1】:
  1. 确保每个线程都有自己的私有 PRNG(所有线程使用一个共享 PRNG 需要锁定,并且由于等待和缓存争用会非常慢)。
  2. Katzgraber 在Random Numbers in Scientific Computing: An Introduction 的第 7.1 节中提出了基于进程/线程号的 PRNG 播种。

看起来像:

long seedgen(void) {
    long s, seed, pid; // pid from 0 to number of processes/threads - 1
    pid = ...; /* get processt/thread ID */
    s = time ( &seconds ); /* get CPU seconds since 01/01/1970 */
    seed = abs(((s * 181) * ((pid - 83) * 359)) % 104729);
    return seed;
}

【讨论】:

  • 这是一个垃圾提案,你的整个再现性概念付诸东流。如果你自己遇到了一个错误,你会怎么做?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-14
  • 2012-09-01
  • 2016-08-08
  • 1970-01-01
  • 2019-07-16
  • 2016-07-22
  • 1970-01-01
相关资源
最近更新 更多