Chr*_*ris 5 c# multithreading synchronization cancellationtokensource cancellation-token
我开发了一个基于 C# 的 Windows 服务,它在几个不同的任务中运行其所有逻辑。为了允许服务在停止时正常关闭,我使用 CancellationToken ,它被传递给任何接受一个的函数(主要来自我正在使用的第三方库),以便在完成之前中止处理。
我注意到,OperationCanceledException当调用函数时请求取消时,这些函数都不会抛出异常,因此我的应用程序只是继续执行,直到我ThrowIfCancellationRequested()稍后在代码中调用其他地方。我是否应该ThrowIfCancellationRequested()在调用每个函数后手动调用以确保任务尽快停止,或者我到底应该何时调用ThrowIfCancellationRequested()自己的代码?
RB.*_*RB. 12
是的,您应该ThrowIfCancellationRequested()在代码中的适当位置手动调用(适当的位置由您作为程序员确定)。
考虑以下简单作业处理函数的示例,该函数从队列中读取作业并对其进行处理。这些评论说明了开发人员在决定是否检查取消时可能会经历的思考。
另请注意,您是对的 - 接受令牌的标准框架函数不会抛出取消异常 - 它们只会提前返回,因此您必须自己检查取消情况。
public async Task DoWork(CancellationToken token)
{
while(true)
{
// It is safe to check the token here, as we have not started any work
token.ThrowIfCancellationRequested();
var nextJob = GetNextJob();
// We can check the token here, because we have not
// made any changes to the system.
token.ThrowIfCancellationRequested();
var jobInfo = httpClient.Get($"job/info/{nextJob.Id}", token);
// We can check the token here, because we have not
// made any changes to the system.
// Note that HttpClient won't throw an exception
// if the token is cancelled - it will just return early,
// so we must check for cancellation ourselves.
token.ThrowIfCancellationRequested();
// The following code is a critical section - we are going to start
// modifying various databases and things, so don't check for
// cancellation until we have done it all.
ModifySystem1(nextJob);
ModifySystem2(nextJob);
ModifySystem3(nextJob);
// We *could* check for cancellation here as it is safe, but since
// we have already done all the required work *and* marking a job
// as complete is very fast, there is not a lot of point.
MarkJobAsCompleted(nextJob);
}
}
Run Code Online (Sandbox Code Playgroud)
最后,您可能不想从代码中泄漏取消异常,因为它们不是“真正的”异常 - 只要有人停止您的服务,它们就会发生。
您可以使用异常过滤器捕获异常,如下所示:
public async Task DoWork(CancellationToken token)
{
try
{
while(true)
{
// Do job processing
}
}
catch (OperationCanceledException e) when (e.CancellationToken == token)
{
Log.Info("Operation cancelled because service is shutting down.");
}
catch (Exception e)
{
Log.Error(e, "Ok - this is actually a real exception. Oh dear.");
}
}
Run Code Online (Sandbox Code Playgroud)