2013-03-05 67 views
4

如果我从C++代码中调用TerminateThread,稍后我会在稍后收到FatalExecutionEngineError MDA。当我对字符串进行不同的操作(即concat)时,这个错误大多发生。下面列出的代码只是显示如何重现它。在C++代码中调用TerminateThread之后在C#代码中检测到FatalExecutionEngineError

为什么会发生?我如何解决它,仍然使用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!!"); 
} 
+7

这正是那种调用TerminateThread可能导致的可怕事情...您应该使用某种形式的同步解决方案来终止您的线程。 – 2013-03-05 15:43:49

+4

“TerminateThread是一个危险的函数,只能在极端情况下使用。**只有当您确切知道目标线程正在执行什么操作时,才应该调用TerminateThread,并且您可以控制目标线程可能存在的所有代码在终止时运行。**“[TerminateThread](http://msdn.microsoft.com/en-us/library/windows/desktop/ms686717 \(v = vs.85 \).aspx)。你通过使用CLR违反了强调的部分。按照@MatthewWatson的建议,以受控的方式终止你的线索。 – user786653 2013-03-05 17:18:59

+1

这个问题确实有一个可能的答案:不要使用TerminateThread。我看不出它会如何做你想做的事(即使你认为它确实如此)。基本上,控制线程执行的所有代码是不可能的。所以你永远不能使用它。 – usr 2013-03-05 21:11:30

回答

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

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

这使得使用TerminateThread()来杀死线程是个问题,比现在更多,它是一个危险的winapi函数,它不执行清理。当它扫描该死亡线程的堆栈时,CLR会翻转。

CLR可以使用Thread :: Abort()执行安全线程异常终止。这样做仍然不是一个好主意,但至少你不会让你的程序非常糟糕。请注意,Abort()在线程运行本机代码时不起作用。完全拒绝这样的想法是最好的,放弃线程是一个好主意。

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