2011-04-04 76 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()沒有任何關係。