0

As a programming exercise I thought it would be fun to try to write a program which uses multiple threads the generate a random number. This method would introduce the "chaos" of the OS scheduler to add randomness.

The idea of 32 threads is that each thread will set a single bit of a number (left shift and 'or' with a random 0/1). They each generate the random bit from a Mersenne Twister engine and just 'and' with 1. EDIT: As Jarod42 pointed out, each thread cant share the same random engine. Assume each thread owns it's own engine.

std::mt19937 eng(/*some std::seed_seq to initialize*/);

At this point, I will describe my ideas towards implementation.

One option is to launch the threads each time the function is called.

unsigned int GetRandom() {
    std::vector<std::thread> myThreads;
    std::mutex numMutex;
    unsigned int num = 0;
    auto BitSetFunction = [&](){
        std::lock_guard<std::mutex> numLockGuard(numMutex);
        num <<= 1;
        num |= eng() & 1;
    };
    for (int i=0; i<32; ++i) {
        myThreads.emplace(myThreads.end(), BitSetFunction);
    }
    for (std::vector<std::thread>::iterator it=myThreads.begin(); it!=myThreads.end(); ++it) {
        (*it).join();
    }
    return num;
}

However the problem I suspected, and sometimes see, is that the creation of the thread is usually slower than the actual locking, setting of the bit, and unlocking. If that is the case the threads will just execute in order and it wont be as interesting. Also the overhead of creating threads for every call to get a random number is huge (I'm assuming).

Is there a more clever way? I thought of creating an object and from it's construction the threads are launched and always running but waiting on a condition variable to know when to crank out a new random number. The problem I hit there was on the destruction of the object, the threads are also destroyed and throw errors because they're still executing.

I'm just curious to hear some other ideas.

Victor Stone
  • 498
  • 5
  • 18
  • 3
    "Is there a more clever way?" Probably--but this is *much* too clever already. – Jerry Coffin Aug 06 '15 at 18:40
  • As the random engine is shared and each thread set the next bit, that doesn't introduce chaos from OS scheduler. – Jarod42 Aug 06 '15 at 18:55
  • [OT]: for range is clearer: `for (auto& thread : myThreads) { thread.join(); }` than the old way with iterator – Jarod42 Aug 06 '15 at 18:58
  • That is clearer, thanks Jarod42. I just realized you're completely correct. No matter which thread gets to run next, its the same engine, and thus the same next number in the sequence. I guess you could give each thread it's own engine. – Victor Stone Aug 06 '15 at 19:04
  • With the same engine, each thread may set a specific bit (to have an OS scheduler *permutation* of the 32 next generated numbers) – Jarod42 Aug 06 '15 at 19:12
  • That's true, rather than each thread taking the least significant bit. – Victor Stone Aug 06 '15 at 20:38
  • Why do you assume the OS scheduling algorithm to be "chaotic"? Do you _require_ chaos? I have not heard of any OS whose scheduling algorithm is _guaranteed_ to be chaotic. – Solomon Slow Aug 06 '15 at 21:50
  • Not necessarily chaotic. However the predictability of processes running seems to be enough to really throw any prediction off. Rather than the random number following a state where no matter when you call it, you'll get the same number. This way, depending on when you call it, you'd get a different number. Depending on the processes running and their priorities, I would expect that it would be very hard to see any pattern. Let alone on top of trying to determine the internal state of the Twister engine. – Victor Stone Aug 06 '15 at 22:03

1 Answers1

0

Let's suppose you have n threads and you want to guarantee that they are practically generating the random number in the same time. You can to something like this:

  • step 1: run all the threads
  • step 2: the threads wait for a similar sign (maybe until a certain moment)
  • step 3: when the sign arrives, all the threads are performing the task
  • step 4: after the task has been completed they give back the output somehow
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • Yeah, that's what I've determined is a good solution. I guess the only problem I'm having is figuring out the proper way to shutdown the threads at the deletion of the object (or just whenever). – Victor Stone Aug 06 '15 at 18:39