C++ srand, rand in a DLL strange behavior
Asked Answered
G

3

5

I'm doing a host for an AI contest, and have a randomBot that choice random possible values.

The bot has 2 exported functions: Init(_seed) and MakeMove()

To play exactly same games host have a defined seed value for each bot. and its passes it in the Init function.

The Init function of random bot has a srand(_seed) function call. The MakeMove function of random bot has a rand() function call.

Now the problem is that after loading 2 bots, each game should be the same with the same seed values, but they are different.

As I know srand should store its value per module/thread and not share it.

I made a test and created a function mysrand and myrand that are not exported with calls to srand and rand respectively.

I replaced the srand and rand inside the exported functions with mysrand and myrand... and it worked...

I have a clue why this is happening but not sure...

So why exactly does it happen and how to avoid it because I want the contestants to use any function they want inside the exported functions (don't want to use my proxy functions).

Thanks.

I'm using windows, compilers: gcc, visual C++, borland C++ builder

Gaygaya answered 10/6, 2012 at 4:26 Comment(2)
I'm using windows, compilers: gcc, visual C++, borland C++ builderGaygaya
There is a similar question asked hereAleph
F
5

If you want to get consistent behavior the <random> library is probably a better choice. You can control where the RNG's state is stored and the engines can produce the same values across implementations (although the standard distributions aren't required to produce the same output across implementations).

#include <random>
#include <iterator>
#include <algorithm>
#include <iostream>

int main() {
    std::mt19937 eng;
    std::generate_n(std::ostream_iterator<int>(std::cout, " "), 10, [&] {
        // A simple example distribution function; not intended for real use.
        return static_cast<int>(eng()/static_cast<double>(eng.max() + 1ull) * 20.0) + 1;
    });
}

This should output the following on all implementations:

17 3 19 17 3 20 19 5 13 7

If you only need consistent behavior within an implementation and not across implementations then you can use the standard distributions, and you'll still have control over where the RNG's state is.

#include <random>
#include <iterator>
#include <algorithm>
#include <iostream>

int main() {
    std::mt19937 eng;
    std::uniform_int_distribution<> dist(1,20);
    std::generate_n(std::ostream_iterator<int>(std::cout, " "), 10, [&] { return dist(eng); });
}

The standard distributions should be preferred over writing your own.

Felonious answered 10/6, 2012 at 6:21 Comment(0)
P
2

As I know srand should store its value per module/thread and not share it.

This is not necessarily true. From rand man page on Ubuntu:

 The function rand() is not reentrant or thread-safe, since it uses hid‐
   den state that is modified on each call.  This might just be  the  seed
   value to be used by the next call, or it might be something more elabo‐
   rate.  In order to get reproducible behavior in a threaded application,
   this  state must be made explicit; this can be done using the reentrant
   function rand_r().

You might end up corrupting RNG state if your C library implementation does not explicitly use local state instead of shared state for rand.

Pomp answered 10/6, 2012 at 4:31 Comment(5)
thanks for the answer, so is there a solution for windows? or I need to use the proxy functions to lock them inside the dll?Gaygaya
@Gaygaya How are you linking to the C runtime library and which C library are you using? If you are linking to the multithreaded C library provided by Microsoft, it should use thread local storage for rand state (apparently).Pomp
for visual C++ I'm using the default configuration, rand/srand from stdlib.h. I also compiled the bot in gcc, and C++ Builder. So I need to make sure that it will work for all the compilers as contestants will have free choice. There might also be a option to overwrite the srand and rand with my own srand and rand with the same functionality but in the bot's interface. But I'm afraid that users can use other random related function like rand_suffle, ...Gaygaya
@Gaygaya Reading the source of Microsoft's CRT implementation shows that it is clearly using thread local storage. Note that if you statically link CRT to the DLL, the DLL will have its own CRT state. (If you want to be platform-neutral and need to work on gcc/linux, you should note that rand is not thread-safe in general, as I mentioned before.)Pomp
It will be platform dependent, only windows dll because of host. As far as I know gcc can't link statically on windows.Gaygaya
B
1

You can link each dll statically to the CRT, it will give each dll its own rand state.

Bela answered 10/6, 2012 at 4:48 Comment(3)
As far as I know gcc can't link statically on windowsGaygaya
I've read, but now also tried, and it conflicts with something, as first run I have one value, second and other runs same other value. compiled with -static compiler argumentGaygaya
VC++ same value... gcc differentGaygaya

© 2022 - 2024 — McMap. All rights reserved.