2011-04-04 78 views
1

我目前正在编写一个roguelike,并且自然会使用大量的随机数生成。RNG崩溃C++程序

我遇到的问题是,如果我“过热”兰德();我的程序会崩溃。

如果我只是每帧产生20左右的整数,那很好......但是当随机数量达到数百时,程序就会崩溃。我制作的每一帧画面越多,它越早崩溃......这导致我相信存在一些堆积现象。

我已经完成了测试,并在20兰特();每帧呼叫,它将以最快速度连续运行24小时而不会崩溃。三倍,并没有使它十分钟。

如果我把srand();在初始化过程中,我可以在锁定之前产生数以千计的随机数 - 但是如果我把srand();在框架本身内,我使它大约2-8帧。如果它很重要,我使用时间(空)来播种。

我更频繁地调用rand();它越早崩溃。

帮助?

+2

你确定它在'rand()'实现中崩溃吗?你用调试器来确认这种行为吗?即使如此,除非你可以在简单情况下重现问题('int main(void){while(1)rand();}')我不会怀疑rand是你的问题。 – 2011-04-04 21:31:15

+0

向我们展示最小的失败示例 – sehe 2011-04-04 21:32:29

+1

您是否从多个线程调用rand? – 2011-04-04 21:32:34

回答

0

如何缩小问题的根源一些意见和想法:

  • 几乎可以肯定不是srand()rand()功能导致崩溃/锁定。机会是一个或多个随机数组合让你的引擎进入发生不好事情的状态。
  • 第一步应该复制问题,使其始终在时间/地点发生。尝试使用像srand(12345)这样的常量种子,而不是使用srand(NULL)。根据你的引擎使用的其他因素(如用户输入),这可能足以让它每次都在同一个地方崩溃。
  • 如果使用调试器有问题(这是可疑的,也许缓冲区溢出损坏堆栈)使用尝试和真正的方法输出消息到文本日志文件。我建议输出所有生成的随机数,也许你可能会在崩溃时看到一个模式(即每当生成“42”时它就会崩溃)。另一个选择是开始在各种功能中添加一些日志消息(从游戏更新循环等高级功能开始)。崩溃后检查日志并开始添加更多日志消息,直到您将其缩小到一行/功能。这并不像使用调试器那么快,但有时候是更好的选择,特别是如果你不知道从哪里开始寻找。
  • 一旦你能够可靠地复制崩溃开始删除的东西,直到崩溃点改变或消失。这可能涉及到#ifdef,注释掉代码,设置应用程序选项,甚至创建项目的临时副本,以便您可以简单地删除代码,编译和测试。如果项目庞大/复杂,这可能会很困难。
  • 有关“崩溃”类型的更多信息将有所帮助。通常,程序不会一般崩溃,但会发生某种异常,锁定等等。异常详细信息可以帮助您通过一些努力缩小问题的根源。
+0

我发现了这个错误,这是我甚至没有收敛的东西 - 敌人最终被其他敌人包围,这会导致他们的移动脚本无限循环并崩溃。而如果被围墙围住,他们只是保持放置,由于某种原因被其他实体包围并没有触发“静止不动”的默认情况,所以“检查相邻方块的碰撞循环将永远持续下去” - 因此总是在碰撞之前不同的时间长度。这是一个具体,独特,挑剔的案例 - 但不可避免,而且更有可能与更多的敌人。 – motioneffector 2011-04-05 00:09:22

1

函数rand()不是可重入的或线程安全的,因为它使用每次调用时都修改过的隐藏状态。这可能只是 被下一次调用使用的种子值,或者它可能更精细一些。为了在线程应用程序中获得可重复的行为,必须明确此状态 。函数rand_r()提供了一个指向unsigned int的指针,用作状态。这是一个非常小的状态,所以这个函数将是一个弱的伪随机生成器。改为尝试drand48_r(3)。

+0

我有同样的想法,但显然这是一个单线程程序。 – 2011-04-04 21:43:43

0
尝试

在调试器下

$ gdb myprog 
(gdb) break main 
(gdb) run 
(gdb) record 

例如运行它

(gdb) break abort 
(gdb) break exit 

,因为它是C++:

(gdb) catch throw 
(gdb) catch exception 

最后 (GDB)继续

当它停,逆向继续,直到找到元凶


选项2:

valgrind --tool=massif --massif-out-file="massif.out.%p" myprog 
ms_print massif.out.* 

检查堆分析。不是不太可能你有内存泄漏

0

兰特的大量呼叫可能会出现在你的代码无法处理的相对较小的范围内的数字。尝试用一个只增加数字并返回它的函数替换你的调用rand,然后查看它是否最终失败。

0
  1. 您可能不应该使用rand()。那里有更好的PRNGs。看看Boost.Random。
  2. 你应该只srand()一次,而不是每一帧。
  3. 找出你的代码崩溃的地方。使用相当简单的调试器,只需在连接调试器的情况下启动程序并等待,直到它崩溃。
  4. 当你发现它崩溃的地方后,找出它崩溃的原因。
  5. 找到原因后,修复它。它可能与rand()没有任何关系。