退出没有循环的线程
本文关键字:线程 循环 退出 | 更新日期: 2023-09-27 17:49:37
我需要一种方法来停止不包含循环的工作线程。应用程序启动线程,然后线程创建一个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 (?)
}
}
...
}
所以我可以处置定时器/FileWatcher时,线程被告知停止-但我如何实际退出/停止线程?
与其使用布尔标志,我建议使用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();
}
这可以防止你使用计时器,你仍然会收到所有的通知。
当Start
方法退出时线程将退出。当你到达计时器的时候,它已经消失了
通常有两种方法
- 使用
Thread.Abort()
中止线程。这在很大程度上被认为是一个非常危险的操作,因为它将有效地抛出一个异常,并使用这个异常退出线程。如果代码准备不充分,这很容易导致资源泄漏或永远锁定互斥锁。我会避免这种方法 - 检查指定位置的
_StopThread
值,然后返回方法或抛出异常以返回到线程开始并从那里优雅地退出线程。这是TPL代码库(取消令牌) 所青睐的方法。
在您的示例中,线程不做任何事情,因为它立即退出。你也可以在主线程中创建观察者对象。
即使创建线程终止,监视程序仍然存在。要删除它,请使用Dispose.
或者,更具体地说,为什么要使用线程?从主线程处理不同线程上的事件?在这种情况下,在Watcher事件处理程序中创建一个新线程。
必须再次小心地执行,以避免创建过多的线程。一个典型的解决方案是使用线程池/后台工作者。
不要使用Thread。开始!
使用TPL, Rx, BackgroundWorker或更高级别的东西
http://msdn.microsoft.com/en-us/library/dd997423.aspx
你不能取消FromAsync任务,因为底层的。net框架api目前不支持正在进行的文件或网络I/O取消。您可以将取消功能添加到封装FromAsync调用的方法中,但是您只能在调用FromAsync之前或在它完成之后(例如,在延续任务中)响应取消。