2008年8月12日 星期二

繪圖執行緒的同步化

嗯...果然不出所料,一開始實做繪圖執行緒,就面臨了幾個問題。

第一個問題是資料的Race Condition,之前已經預期到會有這類問題發生,不過沒有防範完全,所以在一些共享物件的『參考計數』上出狀況。用了兩個函式 InterlockedIncrement 以及 InterlockedDecrement 改掉了這問題。

另一個問題就是當初沒有想到的,也算是對多緒的程式設計還瞭解的不夠透徹所致。把前面的這張圖拿回來看。render_thread一開始,我採用的設計是右邊的這個 Consumer thread 的架構,紅色的邏輯執行緒送指令到佇列,綠色的繪圖執行緒負責從佇列中取出指令來執行。

做法看起來還不錯,但是實際執行就有問題。

問題出在,邏輯執行緒是遊戲程式的主執行緒,而主執行緒會分到相對比較多的執行時間,於是,邏輯執行緒所送給佇列的指令,繪圖執行緒在分到的時間不夠多的狀況下,就沒有辦法及時的處理完。結果就是,邏輯執行緒的Frame rate很高,但是實際畫面的更新率卻非常非常低。

我試了幾個方法,將繪圖執行緒的優先權提高、讓邏輯執行緒Sleep()一下....sync_render_thread最後使用了底下這張圖的方法,在邏輯執行緒與繪圖執行緒之間,建立一個同步的機制,讓邏輯執行緒在接到同步信號之後,才進行下一個Frame的運算。

把繪圖執行緒的優先權提高似乎沒什麼用處,執行緒分到的時間還是少得可憐。而用Sleep函式讓邏輯執行緒睡一下的方法,可以讓佇列中不要累積太多的指令,不過同步的效果並不好,兩個執行緒時快時慢,反而不好控制。

比較起來,同步信號的方式算是比較好的方法。

 

PS. 文章中的兩張圖片,取自Intel在GDC 2008發表的演講內容。

沒有留言: