【发布时间】:2011-09-01 18:00:26
【问题描述】:
问题:
从非托管代码进入CLR 的线程中的未处理异常不会触发“正常”未处理异常 CLR 处理。
在下面的代码中,使用 C++ 调用 CSSimpleObject.GetstringLength()
- “1”在调用线程(非CLR创建的线程)中抛出异常,
- “2”在 new Thread()(CLR 创建的线程)中引发异常。
如果是“1”
- CurrentDomain_UnhandledException() 永远不会被调用。
- Application Domain 和进程将保持加载并运行,您只会收到 FAILED。
情况“2”(预期行为)
- CurrentDomain_UnhandledException() 被调用。
- 进程被杀死。
问题:
必须做什么才能获得“正常”行为?
示例代码:
以下代码基于 Visual Studio 2010“CppHostCLR”代码示例 来自“all interop and fusion samples”。
运行时主机(C++):
PCWSTR pszStaticMethodName = L"GetStringLength";
PCWSTR pszStringArg = L"1";
//PCWSTR pszStringArg = L"2";
hr = pClrRuntimeHost->ExecuteInDefaultAppDomain(pszAssemblyPath,
pszClassName, pszStaticMethodName, pszStringArg, &dwLengthRet);
if (FAILED(hr))
{
wprintf(L"Failed to call GetStringLength w/hr 0x%08lx\n", hr);
goto Cleanup;
}
托管代码 (C#):
public class CSSimpleObject
{
public CSSimpleObject()
{
}
//------8<----------
public static int GetStringLength(string str)
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
switch (str)
{
case "1":
throw new Exception("exception in non-CLR-created thread");
case "2":
Thread thread = new Thread(new ThreadStart(WorkThreadFunction));
thread.Start();
break;
}
return str.Length;
}
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine("CurrentDomain_UnhandledException:" + e.ToString());
Console.ReadKey();
}
public static void WorkThreadFunction()
{
throw new Exception(""exception in CLR-created thread"");
}
研究至今:
MSDN 最初暗示非 CLR 创建的线程中未处理的异常应该或多或少“自然”地表现 - 请参阅“Exceptions in Managed Threads”
公共语言运行时允许线程中大多数未处理的异常自然地进行。在大多数情况下,这意味着未处理的异常会导致应用程序终止。”
“大多数”意味着在 CLR 创建的内部线程中,线程中止和应用程序域卸载异常的处理方式不同。在非 CLR 线程中
“它们正常进行,导致应用程序终止。”
进一步的研究使我找到了“Unhandled Exception Processing In The CLR”,在那里我发现了以下内容:
"如果在托管方法中未处理异常...,该异常将退出 CLR,但继续作为本机 SEH 异常向上传播(托管异常表示为本机 SEH 异常)... OS 未处理异常过滤器 (UEF) 机制可能并不总是导致触发 CLR 的未处理异常处理。 在正常情况下,这会按预期工作,并会触发 CLR 的未处理异常处理。但是,在某些情况下,这可能不会发生。”
上面的代码有什么问题或者怎么改才能触发CLR的未处理异常处理?
更新(2011-05-31):
我刚刚发现了一个旧的错误报告,“当从非托管调用托管代码并引发异常时,未调用 UnhandledExceptionEventHandler - http://tinyurl.com/44j6gvu”,Microsoft 确认这是一个“错误”行为:
感谢您抽出宝贵时间报告此问题。 该行为确实是由 CLR 执行引擎和 CRT 竞争 UnhandledExceptionFilter 引起的错误。 CLR 的架构在支持该场景的 4.0 版本中进行了修改。
更新(2011-06-06):
为什么正确地做到这一点很重要?
- 如果您正在创建托管环境,您的开发人员希望在异常处理中具有一致的行为
- 除非有办法在本机线程中触发“正常 CLR 异常处理”,否则这意味着您必须始终将执行转移到托管线程(例如在线程池中排队)
- 仍有一小部分代码将执行从本机线程转移到托管线程...必须捕获所有异常并以不同方式处理这种情况
注意: 通过 SetActionOnFailure() 更改 CLR 行为会使事情变得更糟,因为它最终会掩盖原始异常(即,您最终会看到 threadAborts 而不是内存不足 - 没有原始错误凸轮的线索)!
【问题讨论】:
-
想知道您是否能够找到解决上述问题 #2 的方法,我遇到了类似的情况
标签: .net c++ exception-handling clr clr-hosting