• ベストアンサー

Delphiのスレッドプログラミング

ゲームプログラムなんですが、計算するルーチンと描画を行うルーチンの二部構成で現在プログラムを作っています。計算は随時行い、描画は余裕があるときに行うというやり方で、最大限のフレームレートを出そうとしています。 で、いままで、Application.onIdleを使って画面描画していたものを、スレッドを使ってみることにしました。メインスレッドで計算を行い、サブスレッドで描画を行うという方法を考えたのですが・・・。 onIdleを使っているうちは、描画が忙しくなってくる→onIdleが発生しなくなる→描画を間引く→負荷が減るといった構図で丁度よかったのですが・・・。 ---------(描画を行うサブスレッド)--------- While(true) do begin   Start := TimeGetTime;   Synchronize(); // ここでメインスレッド経由でVCLに描画   Stop := TimeGetTime;   If (Stop - Start < 33) then Sleep(33 - stop - start); // 描画が33ms以下で済めば、30FPSになるようにwaitを入れる end; ---------------------------------------- このような方法で最大30FPSを確保しようとしたのですが、描画に負荷がかかってくると、メインスレッドにあるタイマが遅延してしまい、全体がガタガタになってしまいました。OnIdle使用時は描画よりメインの数値計算が優先されていたので、問題なかったのですが・・・。 根本的にマズいんでしょうか、コレ・・・。

質問者が選んだベストアンサー

  • ベストアンサー
noname#30727
noname#30727
回答No.3

Delphi の事は全く知りませんが・・・ >Synchronize(); // ここでメインスレッド経由でVCLに描画 メインスレッド経由で描画するという事は、描画に 100ms かかれば、メインスレッドが次のタイマ値を取得できない時間が、少なくとも 100ms は存在するという意味になりませんか? ウィンドウを作成したスレッドでしか、そのウィンドウに描画できないという制限がある場合がありますが、その理由でメインスレッドを経由しなければならないのでしたら、メインとサブを逆にしなければないらないかもしれません。 サブスレッドは描画、メインスレッドは計算とした時、メインスレッドの優先度がサブスレッドのそれよりも高くなくてはならないのはもちろんですが、メインスレッドは33msに1回、入力や描画に必要なオブジェクトリストを必ず作成する。 サブスレッドはタイマを使う必要がなくて、メインスレッドが用意した最新のオブジェクトリストが出来上がるまで待ち、それを描画するようにすれば良さそうです。 メインスレッドが描画の影響を受けないようにするには、オブジェクトリストはメインスレッドが書き込むためのもの、作り終わって待機しているもの、サブスレッドが読み込むためのもの、合計3つを用意してやって、各スレッドがうまく切り替えて使用する事になると思います。

pythian
質問者

お礼

なるほど、勉強になりました。もう少しスレッドに関して勉強してからいろいろいじってみたいと思います。ありがとうございます。

その他の回答 (2)

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

>描画スレッド側でSleepを適度に挟めばいいのでしょうか・・・。 そうでしょうね。 あとは、描画スレッドの優先度を落とすとか。 WindowsAPIならSetThreadPriority()で。

pythian
質問者

お礼

ありがとうございます。優先度を2下げたところ、問題なく動作しました。また、メソッド中で、そのスレッドに割り当てたタイムスライスを解放するように書いたところ、ウソのように症状がよくなりました。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.1

描画が33ms以上かかったときも、Sleepを1msいれてスレッドを描画処理に明渡してあげれば描画されると思います。

pythian
質問者

お礼

ありがとうございます。処理が忙しくなってきたら、サブスレッドの描画は間引いても良いので、メインスレッドの数値計算を行っているタイマーが遅延することだけは避けたいんです。たぶんサブ側が手一杯になるのが原因みたいなので、描画スレッド側でSleepを適度に挟めばいいのでしょうか・・・。

関連するQ&A

専門家に質問してみよう