立即安全地终止线程(C#)

时间:2018-12-01 18:22:08

标签: c# multithreading timer

我正在编写一个简单的“ Score Attack”扑克游戏。玩家在计时器滴答作响时组装值得打分的扑克手。我的问题是游戏过度。

我的游戏逻辑在一个线程中运行,因为游戏本身非常简单。我需要知道如何终止该线程,而播放器不再能够输入。我在MSDN上已经读到,执行此操作的安全方法是使用循环使线程的方法返回并结束线程。我遇到的问题是我的游戏需要用户输入,而用户输入会导致在计时器滴答为零时不检查循环。

到目前为止,该代码使用Thread.Abort(),并且可以正常工作,但是根据我在此站点上的搜索,这通常被认为是一个坏主意。有什么方法可以设置一个条件,以安全地终止线程,而不管所述线程中需要输入什么方法? (Console.ReadLine())

中止线程的游戏循环和计时器回调的代码:

private void GameLoop()
{
    double stash = 0;
    while (true)
    {
    player.SwapCards(gameDeck);
    Table.WriteInfo("Stash This Hand? y/n");              
    if (Console.ReadLine().Equals("y"))
        {
          countdown += (int)ScoreHand(player.Hand);
          stash += ScoreHand(player.Hand); 
          BankHand();
        }             
    }
}


private void TimeDrop(object state)
    {
        countdown--;
        Debug.WriteLine(countdown);
        if (countdown == 0)
        {              
            GameThread.Abort();
            GameOverThread.Start();
            Timer.Dispose();
        }
    }

在它坐着的时候,循环一直运行到线程中止为止。

编辑:

根据请求,代码将启动线程:

 public Game()
    {                    
        gameDeck = new Deck();
        InitPlayer();            
        DealHand();

        countdown = 60;
        GameThread = new Thread(GameLoop);
        GameOverThread = new Thread(GameOver);

        Timer = new Timer(new TimerCallback(TimeDrop), null, 0, 1000);
        Timer.Change(0, 1000); //Ensures timer won't be garbage collected
        GameThread.Start();
    }

1 个答案:

答案 0 :(得分:0)

使用async / await而不是线程可以更轻松,更干净地实现这种事情。

首先,我们需要使用可取消(和异步)的方法包装阻塞控制台输入法。该方法使用KeyAvailable轮询控制台,并在检查CancellationToken时异步延迟。

    public static async Task<ConsoleKeyInfo> ReadKeyAsync(CancellationToken cancellationToken)
    {
        while (!Console.KeyAvailable)
        {
            await Task.Delay(100, cancellationToken);
        }
        return Console.ReadKey();
    }

现在,我们可以启动此异步方法,并从CancellationTokenSource传递取消令牌,该令牌将在特定时间(例如10秒)后自动取消。

    public static async Task Main(string[] args)
    {
        Console.WriteLine("You have 10 seconds to press the Y key...");
        var cts = new CancellationTokenSource(10_000);
        try
        {
            while (true)
            {
                var key = await ReadKeyAsync(cts.Token);
                if (key.Key == ConsoleKey.Y)
                {
                    Console.WriteLine("Good job!");
                    break;
                }
                else
                {
                    Console.WriteLine("Wrong Key");
                }
            }
        }
        catch (OperationCanceledException)
        {
            Console.Write("Time up!");
        }
    }