C# 如何取消一个线程?

C# 如何取消一个线程?,c#,multithreading,C#,Multithreading,在的情况下,可以通过DoWork-事件处理程序的e.cancel-属性报告取消 如何在对象上实现同样的效果?通常,线程的执行是对象上方法的委托,该对象公开一个Cancel属性,长时间运行的操作会定期检查该属性以确定是否退出 比如说 public class MyLongTunningTask { public MyLongRunninTask() {} public volatile bool Cancel {get; set; } public void ExecuteLo

在的情况下,可以通过
DoWork
-事件处理程序的
e.cancel
-属性报告取消


如何在对象上实现同样的效果?

通常,线程的执行是对象上方法的委托,该对象公开一个
Cancel
属性,长时间运行的操作会定期检查该属性以确定是否退出

比如说

public class MyLongTunningTask
{
   public MyLongRunninTask() {}
   public volatile bool Cancel {get; set; }

   public void ExecuteLongRunningTask()
   {
     while(!this.Cancel)
     {
         // Do something long running.
        // you may still like to check Cancel periodically and exit gracefully if its true
     }
   }
}
然后在其他地方:

var longRunning = new MyLongTunningTask();
Thread myThread = new Thread(new ThreadStart(longRunning.ExecuteLongRunningTask));

myThread.Start();

// somewhere else
longRunning.Cancel = true;

阻塞的线程可以通过以下两种方式之一提前停止:

  • 线程。中断

  • 线程终止


主要问题是线程是否在任何需要正确释放的资源上工作——在本例中,您需要使用运行线程的实际对象上的属性

Thread.Abort
,它通过向线程中注入
ThreadAbortException
来工作。这有点冒险,因为:

  • 如果线程当时正在执行本机代码,那么它可能会被卡住
  • 线程中的代码最好是异常安全的,因为这种
    ThreadAbortException
    可能发生在其中的任何代码行上,甚至是像
    i=i+1

  • 最好在GUI线程和后台线程之间编写自己的信令机制。在不知道线程内部发生了什么的情况下,很难推荐一些东西,但是当我有一个线程通过在循环中等待某个对象来工作时,我会使用一个
    自动resetevent
    ,然后再等待它。

    这里是一个完整的例子,说明了一种方法

    private static bool _runThread;
    private static object _runThreadLock = new object();
    
    private static void Main(string[] args)
    {
        _runThread = true;
        Thread t = new Thread(() =>
        {
            Console.WriteLine("Starting thread...");
            bool _localRunThread = true;
            while (_localRunThread)
            {
                Console.WriteLine("Working...");
                Thread.Sleep(1000);
                lock (_runThreadLock)
                {
                    _localRunThread = _runThread;
                }
            }
            Console.WriteLine("Exiting thread...");
        });
        t.Start();
    
        // wait for any key press, and then exit the app
        Console.ReadKey();
    
        // tell the thread to stop
        lock (_runThreadLock)
        {
            _runThread = false;
        }
    
        // wait for the thread to finish
        t.Join();
    
        Console.WriteLine("All done.");    
    }
    

    简言之;线程检查bool标志,并在标志为
    true
    时保持运行。与调用
    线程相比,我更喜欢这种方法。Abort
    因为它看起来更好更干净。

    您需要在Cancel成员上添加volatile,以指示它将从另一个线程更改。很好。如果线程使用“try…”,释放资源不一定是个问题。。。最后,“使用”和/或“使用”每个人都反对中断和中止,所以不要使用它们。很好,不过如果您可以根据
    WaitHandle
    而不是轮询来编写代码会更好。当然,这取决于线程中的代码如何工作。@Tim:是的,WaitHandle可能是一种更干净的方法,而不是像我的示例中那样依赖于共享字段。这也将消除锁定的需要,使代码更切中要害。我不愿意将.NET framework的某些部分(如
    Thread.Abort
    方法)完全错误地调用;我只是在脑海中列出了一些需要避免的技巧。