【问题标题】:Exiting a thread that does not have a loop退出没有循环的线程
【发布时间】:2011-04-11 14:49:12
【问题描述】:

我需要一种方法来停止不包含循环的工作线程。应用程序启动线程,然后线程创建一个 FileSystemWatcher 对象和一个 Timer 对象。其中每一个都有回调函数。 到目前为止,我所做的是将 volatile bool 成员添加到线程类,并使用计时器检查此值。一旦设置了这个值,我就不知道如何退出线程了。

    protected override void OnStart(string[] args)
    {
      try
      {
        Watcher NewWatcher = new Watcher(...);
        Thread WatcherThread = new Thread(NewWatcher.Watcher.Start);
        WatcherThread.Start();
      }
      catch (Exception Ex)
      {
          ...
      }
    }

public class Watcher
{
    private volatile bool _StopThread;

    public Watcher(string filePath)
    {
        this._FilePath = filePath;
        this._LastException = null;

        _StopThread = false;
        TimerCallback timerFunc = new TimerCallback(OnThreadTimer);
        _ThreadTimer = new Timer(timerFunc, null, 5000, 1000);
    }   

    public void Start()
    {
        this.CreateFileWatch();            
    }

    public void Stop()
    {
        _StopThread = true;
    }

    private void CreateFileWatch()
    {
        try
        {
            this._FileWatcher = new FileSystemWatcher();
            this._FileWatcher.Path = Path.GetDirectoryName(FilePath);
            this._FileWatcher.Filter = Path.GetFileName(FilePath);
            this._FileWatcher.IncludeSubdirectories = false;
            this._FileWatcher.NotifyFilter = NotifyFilters.LastWrite;
            this._FileWatcher.Changed += new FileSystemEventHandler(OnFileChanged);

            ...

            this._FileWatcher.EnableRaisingEvents = true;
        }
        catch (Exception ex)
        {
            ...
        }
    }

    private void OnThreadTimer(object source)
    {
        if (_StopThread)
        {
            _ThreadTimer.Dispose();
            _FileWatcher.Dispose();
            // Exit Thread Here (?)
        }
    }

    ...
}

所以我可以在线程被告知停止时处理 Timer / FileWatcher - 但我如何实际退出/停止线程?

【问题讨论】:

  • 我认为如果你使用BackgrundWorker,你可以将你运行线程的表单中包含的变量设置为true
  • 如果可能的话,我想避免重写课程。我已经将其视为其他几个问题的答案 - 我想如果这是正确的做法,我可能不得不这样做。
  • 从表面上看,这个问题具体是关于 I/O 并发的取消流程。是这样吗?
  • 是的。在更改文件时采取的操作之间,我需要停止线程。

标签: c# multithreading concurrency thread-safety io-completion-ports


【解决方案1】:

我建议使用ManualResetEvent,而不是布尔标志。线程启动FileSystemWatcher,然后等待一个事件。当Stop 被调用时,它会设置事件:

private ManualResetEvent ThreadExitEvent = new ManualResetEvent(false);

public void Start()
{
    // set up the watcher
    this.CreateFileWatch();

    // then wait for the exit event ...
    ThreadExitEvent.WaitOne();

    // Now tear down the watcher and exit.
    // ...
}

public void Stop()
{
    ThreadExitEvent.Set();
}

这使您不必使用计时器,并且您仍会收到所有通知。

【讨论】:

  • 我正在修改一些现有代码,并试图使其尽可能接近原始设计。最终,我只是希望线程在文件更改逻辑之间停止 - 而不是在其中一个。此时我不想重新设计服务的逻辑。
【解决方案2】:

Start 方法退出时线程将退出。当您到达计时器时,它已经消失了。

【讨论】:

  • 这很奇怪,因为我虽然是同样的事情 - 但是当安装服务时,这些方法仍然会触发。无论如何,看起来这不是做我需要的正确方法。
  • @Chris:您不需要创建线程来运行 FileSystemWatcher。您只需要通过在某处保留对它的引用来使其保持活力。
【解决方案3】:

一般来说有两种方法可以做到这一点

  • 使用Thread.Abort() 中止线程。这在很大程度上被认为是一个非常危险的操作,因为它会有效地抛出异常并使用它来退出线程。如果代码准备不充分,这很容易导致资源泄漏或永远锁定的互斥锁。我会避免这种方法
  • 在指定位置检查_StopThread 值,然后退出方法或抛出异常以返回线程开始并从那里优雅地退出线程。这是 TPL 代码库(取消令牌)青睐的方法

【讨论】:

  • 看起来只是一个意见。我想看一些代码:)
  • @GregC,你认为哪一部分有意见?
  • CancellationTokens 和类似的工作流程不适用于网络和其他 i/o 操作。请看我的答案,从 MSDN 借来的。
【解决方案4】:

在您的情况下,线程在立即退出时不会做任何事情。您也可以在主线程中创建 Watcher 对象。

即使在创建线程终止后,Watcher 仍然存在。要摆脱它,请使用 Dispose。

或者,更具体地说,您为什么还要使用线程?处理与主线程不同的线程上的事件?在这种情况下,请在 Watcher 事件处理程序中创建一个新线程。

这再次必须小心执行以避免过多的线程创建。一个典型的解决方案是使用线程池/后台工作者。

【讨论】:

    【解决方案5】:

    不要使用 Thread.Start !

    使用 TPL、Rx、BackgroundWorker 或更高级别的东西。

    【讨论】:

      【解决方案6】:

      http://msdn.microsoft.com/en-us/library/dd997423.aspx

      您无法取消 FromAsync 任务,因为底层 .NET Framework API 目前不支持正在进行的文件或网络 I/O 取消。您可以将取消功能添加到封装 FromAsync 调用的方法中,但您只能在调用 FromAsync 之前或完成之后(例如,在延续任务中)响应取消。

      【讨论】:

      • 我质疑是否需要以编程方式进行清理。应用退出时所有后台线程自行退出。
      • 在 i/o 完成端口上启动 i/o 操作时,您可以设置超时。当操作超时时,您可以检查线程是否以循环方式退出。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-08
      • 2018-11-26
      • 2012-05-14
      • 1970-01-01
      • 2014-05-14
      • 2012-11-03
      • 2023-02-23
      相关资源
      最近更新 更多