C# 非托管代码调用托管函数时clr.dll中出现NullReference异常

C# 非托管代码调用托管函数时clr.dll中出现NullReference异常,c#,c++,.net,C#,C++,.net,我有一个托管应用程序,它调用非托管dll,非托管dll也会回调托管应用程序。问题在于非托管dll回调托管代码 有几个测试在我们的CI上间歇性崩溃,并显示消息“代理进程在测试运行时已停止。”。当测试崩溃时,它会创建一个转储文件。转储文件的本机调试会话中的Callstack告诉我们,当非托管dll试图调用托管代码中的函数时,clr.dll引发了异常。下面是调用堆栈,我编写的非托管dll位于底部 KERNELBASE.dll!RaiseException() Unknown clr.dll!Raise

我有一个托管应用程序,它调用非托管dll,非托管dll也会回调托管应用程序。问题在于非托管dll回调托管代码

有几个测试在我们的CI上间歇性崩溃,并显示消息“代理进程在测试运行时已停止。”。当测试崩溃时,它会创建一个转储文件。转储文件的本机调试会话中的Callstack告诉我们,当非托管dll试图调用托管代码中的函数时,clr.dll引发了异常。下面是调用堆栈,我编写的非托管dll位于底部

KERNELBASE.dll!RaiseException() Unknown
clr.dll!RaiseTheExceptionInternalOnly() Unknown
clr.dll!RaiseTheException(class Object *,int,enum CorruptionSeverity)   Unknown
clr.dll!RealCOMPlusThrow(class Object *,enum CorruptionSeverity)    Unknown
clr.dll!Thread::RaiseCrossContextException(class Exception *,class ContextTransitionFrame *)    Unknown
clr.dll!Thread::DoADCallBack(struct ADID,void (*)(void *),void *,int)   Unknown
clr.dll!UM2MDoADCallBack()  Unknown
clr.dll!UMThunkStub()   Unknown
UnManaged.dll!UnManagedClass::CallbackIntoManagedCode(bool * idle) Line 735 C++
UnManaged.dll!UnManagedClass::WhileLoopRunningInSeparateThread() Line 225   C++
到目前为止,我的理论是,如果在包含回调的托管对象被GCed之后,非托管代码被回调回托管代码,那么这可能会发生。我确实发现了一些可能导致这种情况的比赛条件。但即使在修复了这些竞争条件之后,测试仍然会在转储文件中使用此调用堆栈崩溃

问题-

  • 我的理论正确吗

  • 其他可能导致此调用堆栈的场景有哪些

  • 参考代码如下。这和我正在做的很相似。我没有编译这段代码,只是想了解非托管代码是如何调用托管函数的

    // Managed.cs
    public class MyClass
    {
        private int UnmanagedCodeCallsMe(Int64 n, IntPtr c)
        {
            return n;
        }
        public delegate int CalledFromUnmanagedDelegate ( Int64 n, IntPtr c );
        private CalledFromUnmanagedDelegate willBeCalledFromUnmanaged = new CalledFromUnmanagedDelegate(UnmanagedCodeCallsMe);
    
        void StartUseOfCallback()
        {
            // Calls into unmanaged code to set callback
            UnmanagedFunctionSetCallback(willBeCalledFromUnmanaged);
        }
    
        // It is possible that this function never gets called
        void EndUseOfCallback ( )
        {
            UnmanagedFunctionFreeCallback(willBeCalledFromUnmanaged);
        }
    }
    
    ---------------------Over to unmanaged code ----------------
    // Unmanaged.cpp    
    typedef int32 (*ManagedCallback)(int64, int32*);
    public UnmanagedClass
    {
       public:
        ManagedCallback CallManagedCode;
    
        void FreeRunningWhileLoop()
        {
            while(true)
            {
                // Do something
                int32 count;
                CallManagedCode(0, *count);
                // do domething
            }
        }
    
    }
    UnmanagedClass *globalObject;
    
    extern "C" __declspec(dllexport) RegisterManagedFunction(ManagedCallback c)
    {
        globalObject->CallManagedCode = c;
    }
    

    也许,您没有向我们展示测试程序,所以这只是猜测。当MyClass对象被收集时,显示结束。在本机代码中使用全局变量,因此willBeCalledFromUnmanaged应该具有相应的生存期。它应该是
    静态的
    。使用C++/CLI控制台程序测试回调。使用此选项可以调试所有代码。