Hi. So we have this:
const alph = "abcdefghijklmnopqrstuvwxyz1234567890"
randomize()
proc randStr(pref: string): string {.gcsafe.} = #create random string
let alphLen = len alph
var n: int
result = pref
for i in 0 .. 5+random(7):
n = random(alphLen-1)
result &= alph[n]
And I call this function in several threads (I tried protecting it with a lock in assumption it's not thread-safe but it changed nothing). But it returns same values in every thread, e.g. it returns some string in thread1, than the same string in thread2 and so on. This isn't the only problem though, another one is that it returns the same sequence of values every time I run the program.(not tested)
Put the randomize() within the proc, so that the seed is set differently for each thread, rather than each thread sharing the same seed.
Are you on windows using the msvc compiler instead of mingw? The randomize function doesn't do anything if using msvc compiler.
See this snippet from the standard library source code:
when defined(vcc): # Windows with Visual C
proc random(max: float): float =
# we are hardcoding this because
# importc-ing macros is extremely problematic
# and because the value is publicly documented
# on MSDN and very unlikely to change
# See https://msdn.microsoft.com/en-us/library/296az74e.aspx
const rand_max = 4294967295 # UINT_MAX
result = (float(rand()) / float(rand_max)) * max
proc randomize() = discard
proc randomize(seed: int) = discard
@jlp765
Put the randomize() within the proc, so that the seed is set differently for each thread, rather than each thread sharing the same seed.
Thanks, but unfortunately that changed nothing.
@Quikli
Are you on windows using the msvc compiler instead of mingw? The randomize function doesn't do anything if using msvc compiler.
I am on windows, but it is not likely that I use msvc compiler as I downloaded and installed mingw32 and built nim using it. Though, I am not 100% sure about the compiler stuff, so I'll appreciate if you can tell how I can determine if it is the case.
random uses the c function rand, as seen here.
Unfortunately, rand is not safe to use in different threads, as it holds global state.
I think your best option would be to use the nim-random library, which alllows to use different PRNG, and instantiate a different one on each thread (I did not try this, but it should work fine).
Okay I shall give a try to nim-random soon.
I think I came up with a temp solution, at least suitable for my needs as I don't have any limitations about distribution of numbers etc, e.g. I just need random strings and they should be unique inside one thread and differ each time I run the program. So the problem was that randomize was likely to source the seed value from the current unix time and, if I start many threads (50 in my example) at the same time they get the same seed (in fact it is obvious after all) so that the values are also the same. So I introduced a new parameter to a thread proc (num) which in fact is a thread number and used it in combine with current unix time to get a new seed for each thread. So at the start of every thread I do:
proc tp([some_params], num: int) {.gcsafe.}=
randomize(-1*round(((toseconds(gettime())- epochTime())*10000)) + num)
while true:
acquire(K)
id = randStr(pref)
echo id
release(K)
# some other work with id
sleep(300)
#...
var num = 1023 #just a number that came to my mind
for i in 0..49:
spawn tp(..., num)
num += 1023
I use locks just because that won't slow down the program in compare to the time taken by actual work. Though I doubt there's any point in using locks here.
I know this is very ugly and potentially can cause problems but for me it was acceptable at the moment.
Another solution that I thought of was to create a chanal which shall produce random numbers. That may be more thread safe (e.g. random to be called in only one thread) and less hacky, what do you think?