2013-03-05 1 views
4

Если я вызываю TerminateThread из кода C++, то позже я получаю FatalExecutionEngineError MDA позже. Эта ошибка возникает, когда я выполняю разные операции над строками (т. Е. Concat). Код, указанный ниже, просто показывает, как его воспроизвести.FatalExecutionEngineError обнаруживается в коде C# после вызова TerminateThread в коде C++

Почему это происходит? Как я могу исправить и использовать 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 может вызвать ... Вы должны использовать некоторую форму синхронного решения для прекращения ваших потоков. –

+4

«TerminateThread - опасная функция, которая должна использоваться только в самых крайних случаях. ** Вы должны вызывать TerminateThread только в том случае, если вы точно знаете, что делает целевой поток, и вы управляете всем кодом, работающий во время завершения. ** «[TerminateThread] (http: //msdn.microsoft.com/en-us/library/windows/desktop/ms686717 \ (v = vs.85 \) .aspx). Вы нарушаете подчеркнутую часть, используя CLR. Следуйте советам @MatthewWatson и терминами ваших потоков контролируемым образом. – user786653

+1

Существует один ответ на этот вопрос: Не используйте TerminateThread. Я не вижу никакого способа, как это будет делать то, что вы хотите (даже если вы думаете, что это так). В принципе, невозможно контролировать весь код, выполняемый потоком. Поэтому вы никогда не сможете использовать его. – usr

ответ

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

В запущенном потоке запущен управляемый код, а не собственный код на C++. Очевидно, вы скомпилировали это с помощью опции/clr, чтобы вы могли написать код C++/CLI. Это проблема, CLR знает об этом потоке. Обязательно это необходимо, чтобы просмотреть стек потока при запуске сборщика мусора для поиска ссылок на управляемые объекты.

То, что убивает поток с помощью TerminateThread(), является проблемой, больше, чем она есть, это опасная функция winapi, которая не выполняет очистку. CLR падает, когда он сканирует стек этой мертвой нити.

CLR может выполнять безопасные прерывания потока с помощью Thread :: Abort(). Это все еще не рекомендуется, но, по крайней мере, вы не будете сильно заставлять свою программу килить. Обратите внимание, что Abort() не будет работать, когда поток запускает собственный код. Конечно, лучше всего полностью отказаться от идеи, что отмена потоков - хорошая идея.

Очевидное место, где можно попросить прекрасную тему, является инструкцией while (1).