1

Q1: Are pseudo random number generators thread safe? Can I use a shared generator in multiple threads?

#include "stdafx.h"
#include <iostream>
#include <thread>
#include <random>
#include <math.h>  
using namespace std;
random_device seed;//Should I use thread_local here?
default_random_engine engine(seed());//Should I use thread_local here?
int random_int(int x, int y)
{
    binomial_distribution<int> distribution(y - x);
    return distribution(engine) + x;
}
int a[10],b[10],c[10];
void thread_task() {
    for (int i = 0; i < 10; i++)
    {
        a[i] = random_int(1, 8);
    }
}
void thread_task1() {
    for (int i = 0; i < 10; i++)
    {
        b[i] = random_int(1, 8);
    }
}
void thread_task2() {
    for (int i = 0; i < 10; i++)
    {
        c[i] = random_int(1, 8);
    }
}
int main()
{
    thread t(thread_task);
    thread t1(thread_task1);
    thread t2(thread_task2);
    t.join();
    t1.join();
    t2.join();
    for (int i = 0; i < 10; i++)
        cout << a[i] << " ";
    cout << endl;
    for (int i = 0; i < 10; i++)
        cout << b[i] << " ";
    cout << endl;
    for (int i = 0; i < 10; i++)
        cout << c[i] << " ";
    cout << endl;
    getchar();
    return 0;
}

result 1:
7 4 4 3 7 5 4 4 4 4
5 4 4 7 2 3 6 5 4 7
4 4 4 6 1 6 3 5 3 4 //seems fine.
result 2:
5 3 5 6 3 4 5 5 3 5
5 6 5 6 8 3 5 7 3 2
4 6 4 5 4 4 4 3 6 7 //still works fine.

Q2: Does thread safe means lock-free?

If a class is thread safe, then does that mean I can use a shared instance of it in multiple threads without locking it?

Q3: I didn't use either a lock or a thread_local keyword, it still generates different integer sequences for different threads, then what's a lock good for?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
iouvxz
  • 89
  • 9
  • 27
  • 2
    Possible duplicate of [C++11 Thread safety of Random number generators](http://stackoverflow.com/questions/8813592/c11-thread-safety-of-random-number-generators) – Weak to Enuma Elish Dec 06 '15 at 08:27
  • 1
    @James Root No, that post wrote "Just as containers need locks to make them safe to share, you would have to lock the PRNG object. "But I didn't use a lock ,it works fine ,too .I wonder what's the difference . – iouvxz Dec 06 '15 at 08:57

1 Answers1

2

If you don't need deterministic sequences per thread could use use locks with one PRNG. If the pseudo-random sequences can't differ over different threads over different runs then use a PRNG per thread.

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • No, I used a shared generator ,no lock ,on thread_local key word,it returns different integer sequences for each thread . – iouvxz Dec 06 '15 at 08:59
  • Because a sequence generated from two PRNGs does not necessarily give the same guarantees as if you use one (rather unlikely indeed). There are other solutions for generating random numbers for multiple threads without locking though. – Voo Dec 06 '15 at 09:09
  • @Voo I used only one PRNG ,declared as :random_device seed; default_random_engine engine(seed()); – iouvxz Dec 06 '15 at 09:49
  • @iouvxy "returns different integer sequences for each thread" - that's what is meant by *deterministic* or not. As I said. – Paul Evans Dec 06 '15 at 10:08
  • @Paul Evans I'm confused ,sorry for my poor English .I just want random integers for each thread,it seemed that I achieved my goal. But in another post , someone wrote "Just as containers need locks to make them safe to share, you would have to lock the PRNG object. "I didn't ,but my code seems fine ,then what's a lock good for ,I can just use one shared generator . – iouvxz Dec 06 '15 at 10:27
  • @iouvxz We already told you that the c++ random generators are not thread safe (see the comment that links to another question). My point is that using two thread local PRNGs is not generally the same as using one PRNG with a lock around it. The latter guarantees that the sequence of numbers is pseudo-random while the former does **not**. That may or may not be a problem. – Voo Dec 06 '15 at 11:08
  • @Voo I guess it is stupid to use a shared generator without a lock,because threads may read and write at the same time without locking .But ,the distribution part works fine ,the broken data did eventually distribute to the right range ,but that it's still not good practice . – iouvxz Dec 06 '15 at 11:35
  • @iouvxz It's as stupid as writing one past the end of an array because "it's working in this one case I tested with that one compiler". It's undefined behavior, pure and simple. (Also figuring out if it actually is "working" is rather non trivial in case of PRNGs and I assume you didn't run the required statistical test suites against the output to check). – Voo Dec 06 '15 at 11:44