【问题标题】:Terminating a thread immediately and safely (C#)立即安全地终止线程 (C#)
【发布时间】:2019-05-03 13:35:58
【问题描述】:

我正在编写一个简单的“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();
    }

【问题讨论】:

  • 你能展示创建游戏线程的代码吗?
  • 中止线程几乎总是一个坏主意。您可以询问Console 是否有可用的密钥以短暂睡眠,而不是阻止ReadLine 呼叫。
  • @Flydog57 我不确定你的意思。您能否指出您所指的功能或技术?
  • 您需要做的是向另一个线程发送消息并让它自然终止。只有当您试图从您的应用程序中崩溃时,才应拨打任何对Thread.Abort() 的电话。在所有其他情况下,不要调用它。

标签: c# multithreading timer


【解决方案1】:

使用 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!");
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多