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;
}

私はAsyncResult、Jeff Richter の記事「Implementing the CLR Asynchronous Programming Model 」で推奨されているクラスを使用しています。UI からエンジンを停止できるようにするために、私が使用した実装は、標準の非同期パターンから少し離れていました。この実装は期待どおりに機能しますが、標準的な慣行から逸脱した場合は、SO コミュニティに戻って、正しい方法で物事を行っていることを確認します。

この実装には、誰でも見ることができる問題はありますか?

4

2 に答える 2

11

これはあなたが制御できるプロジェクトのように聞こえるので、APM を捨てて、Task.NET4 で提供される ベースのモデルを使用することをお勧めします。これは、APM の代わりに .NET4 に推奨されるアプローチです。このTaskクラスはTask Parallel Library ( 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;
    }
}
于 2011-01-02T06:08:11.693 に答える
2

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

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

于 2011-01-02T06:17:16.180 に答える