CLR托管异常处理在非CLR创建的线程 [英] CLR hosting exception handling in a non-CLR-created thread

查看:278
本文介绍了CLR托管异常处理在非CLR创建的线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

未处理的异常在一个线程进入从非托管code中的 CLR 不会触发了正常未处理除了CLR处理。

An unhandled exception in a thread entering the CLR from unmanaged code does not trigger the "normal" unhandled exception CLR processing.

在以下调用code CSSimpleObject.GetstringLength()从C ++与

In the code below calling CSSimpleObject.GetstringLength() from C++ with

  • 在1抛出调用线程异常(非CLR创建的线程),
  • 在2抛出一个新的线程异常()(CLR创建的线程)。
  • "1" throws an exception in the calling thread (non-CLR-created thread),
  • "2" throws an exception in a new Thread() (CLR-created thread).

在案1

  • CurrentDomain_UnhandledException()不会被调用。
  • 应用领域和进程将保持加载和运行,你只会得到一个失败。
  • CurrentDomain_UnhandledException() is never called.
  • The Application Domain and the process will stay loaded and running, you will only get a FAILED.

在情况下,2(预期行为)

In case "2" (expected behavior)

  • CurrentDomain_UnhandledException()被调用。
  • 的PROCES就会被杀死。

什么必须做,以获得正常的行为?

What has to be done to get the "normal" behavior?

在code以下是基于Visual Studio 2010的 CppHostCLR code样品 从<一href="http://blogs.msdn.com/b/$c$cfx/archive/2010/11/26/all-in-one-interop-and-fusion-$c$c-samples.aspx">all互操作和融合样品的。

The code below is based on the Visual Studio 2010 "CppHostCLR" code sample from the "all interop and fusion samples".

RuntimeHost(C ++):

RuntimeHost (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;
}

管理code(C#):

Managed Code (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创建的线程未处理的异常的行为应该或多或少的自然 - 见的在托管线程例外

公共语言运行时允许在线程中未处理的异常进行自然。在大多数情况下,这意味着未处理的异常会导致应用程序终止。

The common language runtime allows most unhandled exceptions in threads to proceed naturally. In most cases this means that the unhandled exception causes the application to terminate."

大多数,这意味着在CLR创建的线程内,线程终止与应用程序域卸载异常的处理方式不同。在非CLR线程

"Most" meaning that in CLR-created threads internal, thread abort and Application Domain unloaded exceptions are handled differently. In non-CLR threads

他们正常进行,导致终止应用程序。

"they proceed normally, resulting in termination of the application."

进一步的研究使我未处理的异常处理在CLR 里我发现了如下:

Further research led me to "Unhandled Exception Processing In The CLR" where I found out the following:

如果不处理的异常......在管理方法,除了将退出CLR而是继续传播堆栈作为本机SEH异常(管理例外psented原生SEH异常再$ P $) ...   操作系统未处理的异常过滤器(UEF)机制可能并不总是导致触发CLR的未处理的异常处理。   在正常情况下,这将正常工作和CLR的未处理的异常处理将被触发。然而,在某些情况下,这可能不会发生

"if the exception was not handled ... in the managed method, the exception would exit the CLR but continue to propagate up the stack as a native SEH exception (managed exceptions are represented as native SEH exceptions) ... The OS unhandled exception filter (UEF) mechanism may not always result in triggering the CLR's unhandled exception processing. Under normal circumstances, this will work as expected and the CLR's unhandled exception processing will be triggered. However, in certain instances this may not happen."

什么是错的code以上或者怎么能这样CLR的未处理的异常处理被触发?改变

What is wrong with the code above or how can it be changed so that the CLR's unhandled exception processing is triggered?

我刚刚发现了一个古老的bug报告,UnhandledExceptionEventHandler不叫当管理code是从非托管调用,并抛出一个异常 - HTTP:/ /tinyurl.com/44j6gvu ,其中微软证实这是一个越野车的行为:

I just found an old bug report, "UnhandledExceptionEventHandler is not called when managed code is called from unmanaged and throws an exception - http://tinyurl.com/44j6gvu", where Microsoft confirms this is a "buggy" behavior:

感谢您抽出宝贵时间报告此问题。 的行为确实引起由CLR执行引擎和CRT争夺UnhandledExceptionFilter的的一个错误。 CLR的体系结构进行了修订,在4.0版本支持此方案。

Thank you for taking the time to report this problem. The behavior is indeed a bug caused by the CLR execution engine and the CRT competing for the UnhandledExceptionFilter. The architecture of the CLR has been revised in the 4.0 version supporting this scenario.

为什么重要的是得到这个权利?

Update (2011-06-06):

Why is it important to get this right?

  • 如果您要创建一个托管环境的开发人员期望在异常一致的行为处理
  • ,除非有一种方法来触发正常的CLR异常处理在本地线程,这意味着你总是要执行转移到托管线程(在排入队列比如一个线程池)
  • 还有code transfering excecution从原生的微小位,以管理线程......有以不同方式捕获所有异常,不知怎么处理这种情况

注意:改变通过 SetActionOnFailure CLR的行为()使事情变得更糟,在SENCE,它最终掩盖原来的异常(即代替了你的内存endup看到threadAborts - !没有线索,其中从原来的错误CAM)

Note: changing the CLR behavior through SetActionOnFailure() makes matters worse, in the sence, that it ends up masking the original exception (i.e. instead of an out of memory you endup seeing threadAborts - without a clue where the original error cam from)!

推荐答案

更​​新意味着你可能有一个解决方案在这里。但是,它的解决方案将不会在所有情况下工作,所以这里是一些更多的信息。

The update implies that you perhaps have a solution here. However, its solution won't work in all cases, so here is some more info.

如果您preFER CLR未处理的异常行为,然后做出最外面的程序,只调用本地code以执行特定功能。这将确保CLR得到未处理的异常过滤器的控制权。

If you prefer CLR Unhandled Exception behaviour, then make that the outer-most program and call native code only to perform specific functions. That will ensure that the CLR gets control of the unhandled exception filter.

如果您想保留当前的结构和C ++ code你小,你可以停止使用所有的CRT(这将拒绝你一堆有用的东西,包括静态构造函数和C ++异常处理)。这将确保CLR得到未处理的异常过滤器。

If you want to retain your current structure and the C++ code you have is small, you could stop using the CRT at all (which will deny you a bunch of useful stuff including static constructors and C++ exception handling). That will ensure that the CLR gets the Unhandled Exception Filter.

和,当然,你可以简单地调用SetUnhandledExceptionFilter youself,并得到你想要的行为。

And, of course, you could simply call SetUnhandledExceptionFilter youself and get the behaviour you want.

不过,我认为在这种情况下,最好的建议是把实际的功能上,你想要做的事,当发生异常,而不是依赖于UEF机制的任何线程的调用堆栈的catch块 - 因为在一个组件系统的上下文中,它总是脆弱为多个用户竞争它

However, I think the best recommendation in this situation is to put an actual function with a catch block on the call stack of any thread where you want to do something when an exception happens and not rely on the UEF mechanism -- because in the context of a component system, it is always fragile as multiple users compete for it.

马丁

这篇关于CLR托管异常处理在非CLR创建的线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆