我有一种CancellationTokenSource.Cancel永远不会回来的情况.相反,在Cancel调用之后(并且在它返回之前),执行继续执行被取消的代码的取消代码.如果取消的代码随后不会调用任何等待代码,则最初调用的调用者Cancel永远不会获得控制权.这很奇怪.我希望Cancel只记录取消请求并立即独立返回取消本身.Cancel被调用的线程最终会执行属于正在被取消的操作的代码,并且在返回到Cancel看起来像框架中的错误的调用者之前这样做.
以下是这样的:
有一段代码,我们称之为"工作代码",它正在等待一些异步代码.为了简单起见,我们假设这段代码正在等待Task.Delay:
try
{
await Task.Delay(5000, cancellationToken);
// …
}
catch (OperationCanceledException)
{
// ….
}
Run Code Online (Sandbox Code Playgroud)就在"工作者代码"调用之前,Task.Delay它正在线程T1上执行.继续(即"await"之后的行或catch中的块)将在T1或者某些其他线程上执行,具体取决于一系列因素.
Task.Delay.这段代码叫cancellationToken.Cancel.调用Cancel是在线程T2上进行的.我希望线程T2继续返回到调用者Cancel.我还希望catch (OperationCanceledException)在线程T1或T2之外的某些线程上看到很快执行的内容.
接下来发生的事情令人惊讶.我在线程T2上看到,在Cancel调用之后,执行会立即继续执行catch (OperationCanceledException).当这Cancel仍然在callstack上时会发生这种情况.好像呼叫Cancel被代码劫持它被取消了.这是Visual Studio的屏幕截图,显示了这个调用堆栈:
更多背景
下面是关于实际代码的更多上下文:有一个"工作代码"可以累积请求.某些"客户端代码"正在提交请求.每隔几秒"工作代码"就会处理这些请求.处理的请求将从队列中删除.然而,偶尔,"客户端代码"决定它到达希望立即处理请求的点.为了将其传达给"工人代码",它调用Jolt"工人代码"提供的方法.Jolt"客户端代码"调用的方法通过取消Task.Delay由工作者代码主循环执行的方法来实现此功能.工作人员的代码已Task.Delay取消,并继续处理已排队的请求.
实际代码被拆分为最简单的形式,代码可以在GitHub上获得.
环境
该问题可以在控制台应用程序,Universal Apps for Windows的后台代理和适用于Windows Phone 8.1的Universal Apps的后台代理中重现.
该问题无法在Windows的通用应用程序中重现,其中代码按照我的预期运行,并且调用Cancel立即返回.
我有一种情况,我的应用程序有时会在暂停/恢复过程中崩溃.场景如下所示:
Taking the app dump file and examining it using WinDBG shows a call stack like …
考虑我创建MyCustomControlsProject包含一组自定义控件的库的情况.我想在一个非常大的generic.xaml中放置所有这些控件的XAML代码,而不是将每个控件放在自己的XAML文件中,然后从generic.xaml引用该文件.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="<url_syntax_file_1>" />
<ResourceDictionary Source="<url_syntax_file_2>" />
</ResourceDictionary.MergedDictionaries>
Run Code Online (Sandbox Code Playgroud)
解决方案资源管理器(以及文件系统)中的文件夹结构如下所示:
在过去,我使用以下语法在Silverlight和Silverlight for Win Phone中执行此操作:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyCustomControlsProject;Component/Themes/ControlTemplates/MyControl1.xaml"/>
<ResourceDictionary Source="/MyCustomControlsProject;Component/Themes/ControlTemplates/MyControl2.xaml"/>
</ResourceDictionary.MergedDictionaries>
Run Code Online (Sandbox Code Playgroud)
对于使用此语法的Windows Phone 8.1:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Themes/ControlTemplates/MyControl1.xaml" />
<ResourceDictionary Source="ms-appx:///Themes/ControlTemplates/MyControl2.xaml" />
</ResourceDictionary.MergedDictionaries>
Run Code Online (Sandbox Code Playgroud)
这些语法都不适用于Win 10(UWP).尝试使用这些会导致运行时异常:
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException' occurred in MyApplication.exe but was not handled in user code
WinRT information: Failed to assign to property 'Windows.UI.Xaml.ResourceDictionary.Source' because the type 'Windows.Foundation.String' cannot be assigned to the type 'Windows.Foundation.Uri'.
Run Code Online (Sandbox Code Playgroud)
我也试过这种语法导致了同样的异常:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ControlTemplates/MyControl1.xaml" /> …Run Code Online (Sandbox Code Playgroud) c# ×2
async-await ×1
asynchronous ×1
crash ×1
crash-dumps ×1
suspend ×1
task ×1
uwp ×1
windows-10 ×1
xaml ×1