C++ C++;srand、rand在DLL中的奇怪行为

C++ C++;srand、rand在DLL中的奇怪行为,c++,dll,random,srand,C++,Dll,Random,Srand,我正在主持一场人工智能竞赛,有一个随机机器人可以选择随机的可能值 bot有2个导出函数:Init(_seed)和MakeMove() 要玩完全相同的游戏,主机必须为每个机器人定义种子值。并将其传递到Init函数中 random bot的Init函数有一个srand(_seed)函数调用。 random bot的MakeMove函数有一个rand()函数调用 现在的问题是,在加载2个机器人后,每个游戏应该是相同的,具有相同的种子值,但它们是不同的 正如我所知,srand应该存储每个模块/线程的值,

我正在主持一场人工智能竞赛,有一个随机机器人可以选择随机的可能值

bot有2个导出函数:Init(_seed)和MakeMove()

要玩完全相同的游戏,主机必须为每个机器人定义种子值。并将其传递到Init函数中

random bot的Init函数有一个srand(_seed)函数调用。 random bot的MakeMove函数有一个rand()函数调用

现在的问题是,在加载2个机器人后,每个游戏应该是相同的,具有相同的种子值,但它们是不同的

正如我所知,srand应该存储每个模块/线程的值,而不是共享它

我做了一个测试并创建了一个函数myrand和myrand,这两个函数不分别通过调用srand和rand导出

我用myrand和myrand替换了导出函数中的srand和rand。。。它成功了

我有一个线索,为什么会发生这种情况,但不确定

那么,为什么会发生这种情况,以及如何避免这种情况,因为我希望参赛者在导出的函数中使用他们想要的任何函数(不希望使用我的代理函数)

谢谢


<我使用Windows、编译器:GCC、Visual C++、Borland C++ Builder < /P> 正如我所知,srand应该存储每个模块/线程的值,而不是共享它

这不一定是真的。从Ubuntu上的
rand
手册页:


如果您的C库实现没有显式地使用本地状态而不是共享状态来表示
rand

您可以静态地将每个dll链接到CRT,则可能会损坏RNG状态,它将为每个dll提供自己的rand状态。

如果您想要获得一致的行为,那么
库可能是更好的选择。您可以控制RNG状态的存储位置,并且引擎可以跨实现生成相同的值(尽管标准发行版不需要跨实现生成相同的输出)

#包括
#包括
#包括
#包括
int main(){
标准:mt19937英语;
std::generate_n(std::ostream_迭代器(std::cout,“”),10,[&]{
//一个简单的分布函数示例;不适合实际使用。
返回静态转换(eng()/静态转换(eng.max()+1ull)*20.0)+1;
});
}
这将在所有实现中输出以下内容:

17319171732025137

如果您只需要一个实现内的一致行为,而不需要跨实现的一致行为,那么您可以使用标准发行版,并且您仍然可以控制RNG的状态

#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); });
}
#包括
#包括
#包括
#包括
int main(){
标准:mt19937英语;
标准:均匀分布区(1,20);
std::generate_n(std::ostream_迭代器(std::cout,“”),10,[&]{returndist(eng);});
}

与编写您自己的版本相比,应该更喜欢标准发行版。

谢谢您的回答,那么有针对windows的解决方案吗?或者我需要使用代理函数将它们锁定在dll中?@Spider您如何链接到C运行时库以及使用哪个C库?如果您链接到微软提供的多线程C++库,它应该使用线程本地存储来存储代码< > RAND 状态(显然)。我还编译了在GCC中的BOT和C++ Builder。因此,我需要确保它适用于所有编译器,因为参赛者将有自由选择权。也可以选择使用我自己的srand和rand覆盖srand和rand,该srand和rand具有相同的功能,但在机器人的界面中。但我担心用户可以使用其他随机相关函数,如rand_suffle,…@Spider读取Microsoft CRT实现的源代码表明,它显然在使用线程本地存储。请注意,如果将CRT静态链接到DLL,则DLL将具有自己的CRT状态。(如果您希望与平台无关,并且需要在gcc/linux上工作,您应该注意,
rand
通常不是线程安全的,正如我前面提到的那样。)由于主机的原因,它将依赖于平台,只有windows dll。据我所知,GCC不能在Windows上静态链接。我使用Windows、编译器:GCC、Visual C++、Borland C++ + BueLue:有一个类似的问题,我知道GCC不能在Windows上静态链接,但现在也尝试了,它与一些东西冲突,因为第一次运行时,我有一个值,第二个和其他的运行相同的其他值。编译时使用-静态编译器argumentVC++相同值。。。gcc不同
#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;
    });
}
#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); });
}