Problems using rand() in wxThreads Topic is solved

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Blinkinhek
Experienced Solver
Experienced Solver
Posts: 91
Joined: Tue Aug 16, 2005 10:54 am

Problems using rand() in wxThreads

Post by Blinkinhek »

My application uses wxThreads - with a thread being created whenever a particular task needs performing, closing the thread when the task is completed.
I use a rand() to make a random choice when needed (a list sort, where items in the list have an equal 'value').

I find I need to use srand(seed) in the thread itself in order to obtain any form of randomness. If I use a standard srand(tim(NULL)) in the main program rather than the thread, then this has no effect on the randomness sequence I get in the thread ie I will always get the same sequence of numbers.

However I do not want to use srand() in the thread itself. It does work, I now get different random sequences, BUT the seed does not differ very much between one creation of the thread to the next ... and the sequences do not differ greatly (try this yourself in a console program ... seed srand with a slowly incrementing value and generate a few rand()s and see what you get)

I hope I am explaining this ok!
Anyway my questions:
a) why does srand in the main body of the program (in my case I have tried wxApp and a wxFrame) not affect rand() calls in a wxThread?
b) any suggestions on overcoming the problem or alternative rand approaches that would work with wxThread?

TIA
PB
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: Problems using rand() in wxThreads

Post by PB »

1. Can't you use a different (pseudo)random number generator implementation, like Boost's?
2. I believe that seeding must be done in every thread separately, at least on MSVC, as it appears the seed is stored in TLS. This is dependent on CRT implementation, which might differ between compiler vendors.
3. Try initializing the seed from a higher resolution data source (e.g. wxGetUTCTimeMillis().GetLo() ) instead of time().
Blinkinhek
Experienced Solver
Experienced Solver
Posts: 91
Joined: Tue Aug 16, 2005 10:54 am

Re: Problems using rand() in wxThreads

Post by Blinkinhek »

PB wrote:1. Can't you use a different (pseudo)random number generator implementation, like Boost's?
2. I believe that seeding must be done in every thread separately, at least on MSVC, as it appears the seed is stored in TLS. This is dependent on CRT implementation, which might differ between compiler vendors.
3. Try initializing the seed from a higher resolution data source (e.g. wxGetUTCTimeMillis().GetLo() ) instead of time().
I could not find the method you mention, however tried a wxDateTime object setting it to UNow() in a higher process, and used GetMilliseconds(). This is much better than previous results.
I did also try using methods I placed in my wxApp class and used wxGetApp().MyGetRandomNumberMethod() .. but strangely, even though srand was in wxApp and rand() was in wxApp, a call from my thread still resulted in the same 'random' sequence.

Anyway, I am now using your proposed milliseconds scheme.
Many thanks.
Radek
Super wx Problem Solver
Super wx Problem Solver
Posts: 286
Joined: Sun Sep 11, 2011 7:17 am

Re: Problems using rand() in wxThreads

Post by Radek »

PB has already mentioned why. Values that need to be preserved from call to call are stored in the thread local storage.

TLS (thread local storage) is a memory paged to the same linear address for all threads but it is a different physical memory for each thread. A call to rand() uses the memory which is reserved for the thread which is currently running. It does not matter that rand() and srand() are in wxApp - all code is shared between threads. If you initialize in the main thread then the "seed" is stored in the main thread local storage. If you call rand() from the side thread, the side thread uses different physical memory (paged to the same linear address) and it behaves like it was initialized by zero (TLS is zeroized on application startup). That's why you always get the same random sequence if you initialize in the main thread and call rand() from a side thread.

Note that storing in TLS is necessary. Otherwise, the calls from different threads will mutually foul their resulting random numbers. If you are using rand() from different threads then you need to "seed" in all threads which will call rand().

Note: rand() is a congruent RNG, that means a bad RNG. If you need a better random numbers or, especially, if you need random vectors, then do not use rand(). Use, for example, Marsaglia xorshift generators.
RainRat
I live to help wx-kind
I live to help wx-kind
Posts: 178
Joined: Thu Jan 06, 2011 11:26 pm

Re: Problems using rand() in wxThreads

Post by RainRat »

I use a mutex protected, great but slower RNG in my main thread to seed the faster RNG I use in threads. The overhead of the mutex and initial seeding of the thread RNG is relatively negligible, but this guarantees a good new seed for each new thread. This may be overkill or slightly tangent to your question, but suggest it as a possibility for others needing to work with RNGs in threads.
Blinkinhek
Experienced Solver
Experienced Solver
Posts: 91
Joined: Tue Aug 16, 2005 10:54 am

Re: Problems using rand() in wxThreads

Post by Blinkinhek »

Radek wrote:PB has already mentioned why. Values that need to be preserved from call to call are stored in the thread local storage.

TLS (thread local storage) is a memory paged to the same linear address for all threads but it is a different physical memory for each thread. A call to rand() uses the memory which is reserved for the thread which is currently running. It does not matter that rand() and srand() are in wxApp - all code is shared between threads. If you initialize in the main thread then the "seed" is stored in the main thread local storage. If you call rand() from the side thread, the side thread uses different physical memory (paged to the same linear address) and it behaves like it was initialized by zero (TLS is zeroized on application startup). That's why you always get the same random sequence if you initialize in the main thread and call rand() from a side thread.

Note that storing in TLS is necessary. Otherwise, the calls from different threads will mutually foul their resulting random numbers. If you are using rand() from different threads then you need to "seed" in all threads which will call rand().

Note: rand() is a congruent RNG, that means a bad RNG. If you need a better random numbers or, especially, if you need random vectors, then do not use rand(). Use, for example, Marsaglia xorshift generators.
Thanks for the clarifications - clears up my understanding of wxGetApp!
Post Reply