2011-01-02 7 views
7

次のように私は、ゲームエンジンのループを実装している:非同期ゲームエンジンループを実装するためのベストプラクティスはありますか?

public static Boolean Start () 
{ 
    if (hasBoard) 
    { 
     // start engine on worker thread 
     asyncTask = new AsyncResult (stopEngine, asyncTask); 
     isRunning = ThreadPool.QueueUserWorkItem (startEngine, asyncTask); 

     if (isRunning) 
     { 
      Console.WriteLine ("[{0}] Engine started", 
       DateTime.Now.ToString ("hh:mm:ss")); 
     } 
     else 
     { 
      Console.WriteLine ("[{0}] Engine failed to start", 
       DateTime.Now.ToString ("hh:mm:ss")); 
     } 
    } 

    return isRunning; 
} 

public static void Stop () 
{ 
    Console.WriteLine ("[{0}] Engine stopping", 
     DateTime.Now.ToString ("hh:mm:ss")); 

    asyncTask.SetAsCompleted (null, false); 
} 

private static void startEngine (Object task) 
{ 
    while (!((IAsyncResult)task).IsCompleted) 
    { 
     Thread.Sleep (10000); 

     Console.WriteLine ("[{0}] Engine running", 
      DateTime.Now.ToString ("hh:mm:ss")); 
    } 
} 

private static void stopEngine (IAsyncResult iaResult) 
{ 
    // clean up resources 

    Console.WriteLine ("[{0}] Engine stopped", 
     DateTime.Now.ToString ("hh:mm:ss")); 

    isRunning = false; 
} 

私は彼の記事、Implementing the CLR Asynchronous Programming Modelにジェフ・リヒターが推奨するAsyncResultクラスを使用しています。 UIからエンジンを停止できるように、私が使った実装は、標準の非同期パターンからちょっと離れていました。この実装は期待どおりに機能しますが、標準的な習慣から逸脱すると、私はSOコミュニティに戻って、正しい方法で作業するようにします。

誰にでも見えるこの実装に関する問題はありますか?

+0

ゲームエンジンのループでは、単にプールスレッドを使用するのではなく、 –

+0

@Mitch:わかりません。私は新しい糸を産むことが標準だと信じています。私は、スレッドプールスレッドを使用して何か問題があることを知らない。このゲームエンジンは超軽量です。また、WinFormsのUIは*制御されているので、これはゲームループを動作させる良い方法だと思っていました。 – IAbstract

+1

ゲームループで*スレッドを使用しているのはなぜですか?あなたが*必要なものがあれば(本当によく質問されるべきです)、スレッドは、キューから取り除かれる特定の明確に定義された目的*(例えば、常時2つのスレッドなど常に)または他の同期。しかし、それを「キス」にしておくのが最もよいでしょう。 –

答えて

11

これはあなたがコントロールしているプロジェクトのように聞こえるので、私はあなたにAPMを捨て、.NET4で提供されているTaskベースのモデルを使用することをお勧めします。これは、APMではなく.NET4の推奨アプローチです。 Taskクラスはタスク並列ライブラリTPL)の一部ですが、これらの基本的な非同期ジョブにも最適です。

private CancellationTokenSource cts; 

public void StartEngine() 
{ 
    if (cts == null) 
    { 
     cts = new CancellationTokenSource(); 
     Task.Factory.StartNew(() => GameLoop(cts.Token), cts.Token); 
    } 
} 

private void GameLoop(CancellationToken token) 
{ 
    while (true) 
    { 
     token.ThrowIfCancellationRequested(); 
     Thread.Sleep(1000); 
     Debug.WriteLine("working..."); 
    } 
} 

public void StopEngine() 
{ 
    if (cts != null) 
    { 
     cts.Cancel(); 
     cts = null; 
    } 
} 
+2

合意しましたが、タスクを作成するときにLongRunningオプションを追加します。 –

+0

私は、LongRunningオプションを追加するように変更しました: 'Task.Factory.StartNew(()=> startEngine(cancelSource.Token)、cancelSource.Token、TaskCreationOptions.LongRunning、TaskScheduler.Default); ' – IAbstract

2

私は、スレッドプールのスレッド数が限られているため、スレッドプールを使用するとタスクが短命であることを暗示しています。

winformsについて言及したので、代わりにBackgroundWorkerを使用します。 BWはあなたのために同期を処理します。したがって、InvokeRequiredなどを使用せずにGUIを更新することができます。

+0

*タスクは以下のとおりです。私は本当に何かを逃していない限り、* Jeff Richterによるものではなく、スレッドプール*を使用すると短命です。しかし、私はスレッドプールのスレッドタスクを短く保つことにあなたのポイントを参照してください。 – IAbstract

+0

@IAbstract:それについての参考資料はありますか?読むのは面白いでしょうか。 – jgauffin

+0

私はもう一度それを見つけなければならないでしょう - 私はコメントをしてから1年半を超えています。タスクが短命であるということは、デフォルトの処理によるものである可能性があります。つまり、長い実行時間が必要な場合は、長時間実行するタスクを設定する必要があります。私がコメントしたものに意味のあるものがあったに違いないが、私が言及しているものを見つけようとするだろう。 ;) – IAbstract

関連する問題