在 C++ 代码中调用 TerminateThread 后在 C# 代码中检测到 FatalExecutionEngineError

Posted

技术标签:

【中文标题】在 C++ 代码中调用 TerminateThread 后在 C# 代码中检测到 FatalExecutionEngineError【英文标题】:FatalExecutionEngineError detected in C# code after calling TerminateThread in C++ code 【发布时间】:2013-03-05 15:41:24 【问题描述】:

如果我从 C++ 代码调用 TerminateThread,那么稍后我会得到 FatalExecutionEngineError MDA。该错误主要发生在我对字符串(即 concat)执行不同操作时。下面列出的代码只是展示了如何重现它。

为什么会这样?如何修复它并仍然使用 TerminateThread?

谢谢

错误是:

FatalExecutionEngineError was detected
Message: The runtime has encountered a fatal error. 
The address of the error was at 0x7880bb35, on thread 0x18f0. 
The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. 
Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.

C++ 代码: 模块.cpp:

#include "ThreadModule.h"
using namespace ThreadModule;

DWORD WINAPI workThread(LPVOID lpParam) 
    while(1) 
        System::Threading::Thread::Sleep(5);
        printf(".");
    
    return 0;


bool Module::StartThread() 
    handle = CreateThread(
        NULL,
        0,
        workThread,
        NULL,
        0,
        &threadIdInput);
    return true;    


bool Module::StopThread() 
    TerminateThread(handle, 0);
    handle = NULL;
    return true;

C# 代码:

static void Main(string[] args)

    Module module = new Module();

    module.StartThread();
    string s = "";
    for (int i = 0; i < 10000; i++)
    
        s += i.ToString();
    
    module.StopThread();
    s = "";
    for (int i = 0; i < 10000; i++)
    
        s += i.ToString();  //After ~250 iteration get exception
    
    Console.WriteLine("Completed!!");

【问题讨论】:

这正是调用 TerminateThread 可能导致的那种可怕的事情......您应该使用某种形式的同步解决方案来终止您的线程。 "TerminateThread 是一个危险的函数,只应在最极端的情况下使用。只有在您确切知道目标线程在做什么并且您可以控制所有线程的情况下才应该调用 TerminateThread目标线程在终止时可能正在运行的代码。" TerminateThread。您使用 CLR 违反了强调的部分。听从@MatthewWatson 的建议,以可控的方式终止你的线程。 这个问题只有一个可能的答案:不要使用 TerminateThread。我看不出它会如何做你想做的事(即使你认为它会做)。基本上,不可能控制线程执行的所有代码。所以你永远不能使用它。 如果您决定继续使用 TerminateThread,但从您的本机类中删除所有 CLR 代码,则需要另外使用 #pragma managed(off)。在我自己的使用 TerminateThread 的代码中(顺便说一下,在我的情况下,这是不可避免的),在添加编译指示之前,我一直在遇到内存损坏。即使我的本机类中的 CLR 代码为零,这也是必要的。 【参考方案1】:
   System::Threading::Thread::Sleep(5);

您启动的线程正在运行托管代码,而不是本机 C++ 代码。显然,您使用有效的 /clr 选项编译了它,因此您可以编写 C++/CLI 代码。这是一个问题,CLR 知道那个线程。必然如此,它需要在运行垃圾收集器时查看线程的堆栈以查找托管对象引用。

这使得用 TerminateThread() 杀死线程是个问题,比现在更严重的是,它是一个危险的 winapi 函数,它不执行任何清理操作。当 CLR 扫描死线程的堆栈时,它会崩溃。

CLR 可以使用 Thread::Abort() 执行安全的线程中止。这样做仍然不是一个好主意,但至少你不会让你的程序严重失败。请注意,当线程运行本机代码时,Abort() 将不起作用。最好完全放弃中止线程是个好主意的想法。

while(1) 语句是让线程很好地停止的一个明显地方。

【讨论】:

以上是关于在 C++ 代码中调用 TerminateThread 后在 C# 代码中检测到 FatalExecutionEngineError的主要内容,如果未能解决你的问题,请参考以下文章

在 WP8 中从 C++ 代码调用 C# 方法

使用 Ctypes 调用复杂的 c++ 代码

初学者在 C++ 中调用函数,代码编译数学是错误的

在日志记录中禁用函数调用或禁用代码行 C++

使用 c# 中的 c++ 引用中的引用从 C# 错误调用 C++ 代码

从 c# 调用 C++ 代码