3

我需要一种方法来停止不包含循环的工作线程。应用程序启动线程,然后线程创建一个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 - 但是我如何实际退出/停止线程?

4

6 回答 6

2

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

于 2011-04-11T14:54:22.463 回答
2

我建议不要使用布尔标志,而是使用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();
}

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

于 2011-04-11T15:19:07.193 回答
1

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

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

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

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

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

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

于 2011-04-11T15:07:25.837 回答
0

不要使用 Thread.Start !

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

于 2011-04-11T14:55:55.463 回答
0

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

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

于 2011-04-11T15:08:13.327 回答