我正在开发一个WPF应用程序,它将作为后台任务运行“索引服务”。索引服务将使用监视文件夹的FileSystemWatcher - 当文件更改时,索引服务将读入文件内容并更新索引(我使用的是Lucene.Net)。我的索引服务是一个单例,将在应用程序启动期间启动,如下所示: -
new TaskFactory().StartNew(_indexingService.StartService);
StartService()
方法如下所示: -
private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false);
public void StartService()
{
var watcher = new FileSystemWatcher
{
// Set the properties
};
watcher.Changed += UpdateIndexes();
_resetEvent.WaitOne();
}
当应用程序关闭时,我打算调用此方法,据我所知,它将结束索引服务后台任务: -
public void StopService()
{
_resetEvent.Set();
}
首先,这是启动和停止应该在应用程序生命周期内运行的后台任务的正确“模式”吗?
其次,这种关闭会有多“优雅”?假设观察者Changed
事件处理程序已经触发并正在迭代文件,读取它们并更新索引。如果任务已停止,是否会在流程中中止此处理,或者事件处理程序方法是否会先运行完成?
答案 0 :(得分:3)
您可以使用取消令牌:
CancellationTokenSource CancelationToken = new CancellationTokenSource();
new TaskFactory().StartNew(_indexingService.StartService,CancelationToken,
TaskCreationOptions.LongRunning)
.ContinueWith(TaskCancelationCallBack,TaskContinuationOptions.OnlyOnCanceled);
您可以使用以下方式在应用程序中的任何位置取消令牌:
CancellationTokenSource.Cancel();
您可以检查您的令牌是否被取消,并从内部抛出取消异常任务:
if (CancelationToken.IsCancellationRequested) {
CancelationToken.Token.ThrowIfCancellationRequested();
}
您可以在ContinueWith回调中获取任务状态:
private void TaskCancelationCallBack(System.Threading.Tasks.Task task)
{
if (task.Status == System.Threading.Tasks.TaskStatus.Canceled)
{
//Canceled
}
}
编辑:在这种情况下,我们使用了TaskContinuationOptions.OnlyOnCanceled
,因此无需检查TaskCancelationCallBack。它只会在这个前提下解雇。
答案 1 :(得分:1)
@Carlos Landeras
ThrowIfCancellationRequested检查是否请求取消,因此嵌入检查相同的if语句是多余的。
This method provides functionality equivalent to:
if (token.IsCancellationRequested)
throw new OperationCanceledException(token);
答案 2 :(得分:0)
如果你取消了对waitOne的调用,那么任务就会结束。
要让后台任务真正做某事,在某些时候需要有一个循环来处理,比如
void ProcessItems()
{
while(workItems.Count > 0)
{
ProcessItem(workItems[0]);
}
}
如果你想优雅地拯救,你可以做两件事。在我的例子中,我会有一面旗帜。
bool m_IsRunning = true;
public void Stop()
{
m_IsRunning = false;
}
void ProcessItems()
{
while(workItems.Count > 0 && m_IsRunning)
{
ProcessItem(workItems[0]);
}
}
使用任务并行库,您还可以传入CancellationToken
。
在任务类中,取消涉及到之间的合作 user delegate,表示可取消的操作和代码 要求取消。取消成功涉及到 请求代码调用CancellationTokenSource.Cancel方法, 并且用户委托及时终止操作。 您可以使用以下选项之一终止操作:
只需从代表返回即可。在许多情况下,这已足够;但是,以这种方式“取消”的任务实例
转换到RanToCompletion状态,而不是转换为Canceled状态。通过抛出OperationCanceledException并将请求取消的令牌传递给它。这样做的首选方法是
使用ThrowIfCancellationRequested方法。一项任务是 以这种方式取消转换到已取消状态,其中 调用代码可用于验证任务是否响应其中 取消请求。