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
Problems using rand() in wxThreads Topic is solved
-
- Experienced Solver
- Posts: 91
- Joined: Tue Aug 16, 2005 10:54 am
Re: Problems using rand() in wxThreads
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().
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().
-
- Experienced Solver
- Posts: 91
- Joined: Tue Aug 16, 2005 10:54 am
Re: Problems using rand() in wxThreads
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.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 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.
Re: Problems using rand() in wxThreads
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.
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.
Re: Problems using rand() in wxThreads
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.
-
- Experienced Solver
- Posts: 91
- Joined: Tue Aug 16, 2005 10:54 am
Re: Problems using rand() in wxThreads
Thanks for the clarifications - clears up my understanding of wxGetApp!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.