4

如果我从 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++ 代码:
Module.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!!");
}
4

1 回答 1

4
   System::Threading::Thread::Sleep(5);

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

这使得用 TerminateThread() 杀死线程是个问题,比现在更多的是,它是一个危险的 winapi 函数,它不执行任何清理操作。CLR 在扫描该死线程的堆栈时发生故障。

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

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

于 2013-03-05T20:14:13.340 回答