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

Posted

技术标签:

【中文标题】立即安全地终止线程 (C#)【英文标题】:Terminating a thread immediately and safely (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() 的电话。在所有其他情况下,不要调用它。 【参考方案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!");
        
    

【讨论】:

以上是关于立即安全地终止线程 (C#)的主要内容,如果未能解决你的问题,请参考以下文章

如何在退出前安全地关闭所有线程[重复]

安全终止MFC线程

如何以线程安全的方式退出 C++03 中的程序?

Linux-线程终止-线程等待-线程分离-线程安全

安全线程终止

如何在 C# 中立即杀死一个线程?