簡體   English   中英

Clang 是否比跨平台的 GCC 更具確定性?

[英]Is Clang more deterministic than GCC across platforms?

我正在考慮在 C++ 中(部分)編寫多用戶 RTS 游戲的可行性。 我很快發現,一個硬性要求是游戲模擬必須完全確定服務器和所有客戶端的最后一點,以便能夠將網絡通信限制為用戶輸入,而不是游戲 state 本身. 由於每個人都有不同的計算機,這似乎是一個難題。

那么,是否有一些“神奇”的方法可以讓 C++ 編譯器創建一個跨 Linux(服務器)、Windows 和 Mac 完全確定的可執行文件? 我認為兩個主要的 OSS C++ 編譯器是 GCC 和 Clang,所以我想知道在這方面是否有一個比另一個更好。

我也會對任何可用於驗證 C++ 確定性的測試套件感興趣。

[編輯] 通過確定性,我的意思是編譯的程序,給定相同的初始 state,並以相同的順序輸入,將始終在它運行的任何平台上產生相同的 output。 所以,也是跨網絡。 對我來說,一致聽起來像是對這種行為的恰當定義,但我不是母語人士,所以我可能會誤解確切的含義。

[EDIT#2] 雖然關於確定性/一致性是否重要的討論,以及我是否應該在游戲引擎中以此為目標,以及它在 C++ 中通常有多大的問題,是非常有趣的,它並沒有以任何方式真正回答問題。 到目前為止,沒有人知道我是否應該使用 Clang 或 GCC 來獲得最可靠/確定性/一致的結果。

[EDIT#3] 我突然想到有一種方法可以在 C++ 中獲得與在 Java 中完全相同的結果。 必須采用 JVM 的開源實現,並提取實現運算符和數學函數的代碼。 然后你把它變成一個獨立的庫,並在其中調用內聯函數,而不是直接使用運算符。 手工操作會很痛苦,但是如果生成代碼,那么它是一個完美的解決方案。 也許這甚至可以通過類和運算符重載來完成,所以它看起來也很自然。

由於每個人都有不同的計算機,這似乎是一個難題。

它不是。 真的,這種網絡非常簡單,只要你不做任何規范未定義的事情。 IEEE-754對如何進行浮點數學運算、如何進行舍入等非常清楚,並且跨平台實現相同。

您不需要做的最重要的事情是在需要確定性的代碼中依賴 SIMD CPU 指令(注意:這是物理、人工智能等:游戲 state。不是圖形,這是您需要 SIMD 的地方)。 這些類型的指令在浮點規則中運行得又快又松。 所以你的游戲代碼中沒有 SIMD; 僅在“客戶端”代碼(圖形、聲音等)中。

此外,您需要確保您的游戲 state 不依賴於時間等因素; 每個游戲 state 時鍾滴答應該是一個固定的時間間隔,而不是基於 PC 的時鍾或任何類似性質的東西。

顯然,你應該避免任何你沒有代碼的隨機 function 。 但同樣,僅適用於您的主要游戲循環; 圖形內容可以是特定於客戶端的,因為它只是視覺效果,並不重要。

就保持兩個游戲狀態同步而言,差不多就是這樣。 您使用的編譯器對您來說不會是一個大問題。

請注意,星際爭霸和星際爭霸 II 使用此作為其網絡 model 的基礎。 它們都在 Mac 和 PC 上運行,並且都可以互相對抗。 所以很有可能,不需要Clang。

雖然如果你喜歡 Clang,你應該使用它。 但這應該是因為你喜歡它,而不是因為網絡。

不要依賴未定義或未指定的行為,(特別是不要使用浮點),使用什么編譯器都沒有關系。

如果a為 1, b為 2,則a + b為 3。這是由語言標准保證的。

C++ 不是在某些編譯器中某些事物是“確定性”的,而在其他編譯器中則不是。 C++ 陳述了一些事實(如 1 + 2 == 3)並將一些事情留給編譯器(如 function 參數的評估順序)。 如果您的程序的 output 僅依賴於前者(和用戶的輸入),並且您使用符合標准的編譯器,那么在給定相同的用戶輸入的情況下,您的程序將始終生成相同的 output。

如果您的程序的 output 也取決於(比如說)用戶的操作系統,那么程序仍然是確定性的,只是 output 現在由用戶的輸入和他們的操作系統確定。 如果您希望 output 僅依賴於用戶的輸入,則由您來確保用戶的操作系統不是您程序的 output 的影響因素。 一種方法是僅依賴語言標准保證的行為,並使用符合該標准的編譯器。

總之,所有代碼都是確定性的,基於其輸入。 您只需要確保輸入僅由您想要的內容組成。

我認為您使用的編譯器並不重要。

例如,在 Doom 中使用了這種完全確定的方法。 他們使用的是固定的“隨機”數數組,而不是隨機數生成器。 游戲時間以游戲中的時間來衡量(如果我記得的話,大約是 1/30 秒)。

如果您通過游戲內機制來衡量所有內容,而不是將您的工作卸載到可能有各種版本的標准庫中,我相信您應該在不同機器上實現良好的可移植性。 當然,前提是這些機器的速度足以運行您的代碼!

但是,網絡通信本身可能會產生問題:延遲、掉線等。您的游戲應該能夠處理延遲消息,並在必要時自行重新同步。 例如,您可能希望不時發送完整的(或至少:更詳細的)游戲 state,而不是僅依賴用戶輸入。

還要考慮可能的漏洞:

  • 客戶:我在扔手榴彈
  • 服務器:你沒有手榴彈
  • 客戶:我不在乎。 盡管如此,我還是在扔手榴彈

這有點愚蠢。 在大端機器與小端機器上,或在 64 位機器與 32 位機器與其他一些隨機機器上,您的程序不會“完全確定”(無論如何)“到最后一點”。

說到隨機,很多游戲都有隨機的元素。 如果您通過調用 c 標准 function rand() 來實現這一點,那么所有的賭注都沒有了。

如果您開始使用浮點數,您的所有賭注都將被取消。 即使在同一個平台上,您也會遇到難以發現/修復的問題,只需選擇 Intel 或 AMD cpu。

許多運行時庫為不同的芯片優化了代碼路徑。 這些都在規范范圍內,但有些比這更精確。 這會導致細微的舍入誤差,遲早會累積到可能破壞事物的差異。

您的目標應該是在沒有 100% 確定性的情況下逃脫。 畢竟:如果對手比它應該在左邊多一個像素,這對玩家有影響嗎? 它不是。 重要的是,客戶端和服務器之間的微小差異不會破壞游戲玩法。

玩家在屏幕上看到的內容應該是確定性的,所以他不會感到被欺騙,但這絕不是必需的。

我從事的游戲通過不斷地在所有客戶端之間重新同步所有實體的游戲狀態來存檔這一點。 然而,我們幾乎從未發送過整個游戲狀態,但我們發送了游戲 state,每幀的幾個對象在幾秒鍾內分配了作業。

只要給最重要的對象比其他對象更高的優先級就可以了。 例如,在賽車游戲中,如果對手汽車離你很遠,那么精確的 position 並不重要,只需要每 20 秒左右更新一次就可以了。

在這些更新之間,請相信小的舍入錯誤不會累積太多以至於您遇到麻煩。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM