2010-08-09 2 views
4

우리는 하나의 스레드가 SuspendThread/GetThreadContext/ResumeThread를 수행하여 상태 [PC 등]를 검사하도록 다른 스레드를 중지시킬 수있는 Windows32 응용 프로그램을 보유하고 있습니다.Windows SuspendThread가 아닙니까? (GetThreadContext 실패)

if (SuspendThread((HANDLE)hComputeThread[threadId])<0) // freeze thread 
    ThreadOperationFault("SuspendThread","InterruptGranule"); 
CONTEXT Context, *pContext; 
Context.ContextFlags = (CONTEXT_INTEGER | CONTEXT_CONTROL); 
if (!GetThreadContext((HANDLE)hComputeThread[threadId],&Context)) 
    ThreadOperationFault("GetThreadContext","InterruptGranule"); 

는 매우 드물게, 멀티 코어 시스템에서 GetThreadContext 오류 코드 5 (윈도우 시스템 오류 코드 "액세스가 거부") 반환하지 않습니다.

SuspendThread 설명서는 오류가 반환되지 않으면 대상 스레드가 일시 중단되었음을 명확하게 나타냅니다. SuspendThread 및 ResumeThread의 반환 상태를 확인하고 있습니다. 그들은 이제까지 불평하지 않고 있습니다.

스레드를 일시 중단 할 수 있지만 해당 컨텍스트에 액세스 할 수없는 경우 어떻게 수 있습니까? http://www.dcl.hpi.uni-potsdam.de/research/WRK/2009/01/what-does-suspendthread-really-do/

이 블로그는, SuspendThread로, 그것은 반환 할 때, 다른 스레드의 정지 시작 수 있음을 시사하지만 스레드는 아직 중단되지 않았습니다. 이 경우 GetThreadContext가 어떻게 문제가되는지 알 수는 있지만 SuspendThread를 정의하는 것은 어리석은 방법입니다. (대상 스레드가 실제로 일시 중단 된 시점을 SuspendThread가 어떻게 알 수 있습니까?)

EDIT : 거짓말. 나는 이것이 Windows 용이라고 말했다.

이상한 진실은 Windows XP 64에서이 동작을 볼 수 없다는 것입니다. (적어도 지난 주에는 없었으며 그 전에는 어떤 일이 발생했는지 모릅니다.) 그러나 우리는 테스트를 거쳤습니다. Ubuntu 10.x의 Wine에서이 Windows 응용 프로그램. Wine source for the guts of GetThreadContext에는 어떤 이유로 든 스레드 상태를 가져 오지 못하면줄에 819의 액세스 거부 응답이 포함되어 있습니다. 추측 하건데, Wine GetThreadStatus는 스레드가 반복적으로 액세스 할 수 없다고 생각합니다. SuspendThead가 나를 넘어선 뒤에는 그것이 사실 일 것입니다.하지만 코드가 있습니다. 생각?

EDIT2 : 다시 거짓말했습니다.. 나는 우리가 와인에서만 그 행동을 보았다고 말했다. 아니 ... 우리는 이제 동일한 오류 (다시는 드물게)를 생성하는 것으로 보이는 Vista Ultimate 시스템을 발견했습니다. 따라서 와인과 Windows는 모호한 경우에 동의합니다. 또한 Sysinternals Process 모니터 프로그램을 단순히 활성화하면 상황이 심각 해지고 Windows XP 64에 문제가 발생합니다. 나는 Heisenbug를 의심한다. (Process Monitor 은 Wine-tasting (:-) 기계 또는 개발 용으로 사용하는 XP 64 시스템에도 존재하지 않습니다.

지구상에 무엇이 있습니까?

EDIT3 2010 년 9 월 15 일. SuspendThread, ResumeThread 및 GetContext에 대해 코드를 방해하지 않고 오류 반환 상태를 신중하게 확인했습니다. 나는 그것을 한 이후로 어떤 힌트를 Windows 시스템에서 보았습니다. 와인 실험으로 돌아 가지 않았습니다.

2010 년 11 월 : Strange. VisualStudio 2005에서 컴파일하면 Windows Vista 및 7에서는 실패하지만 이전 OS에서는 실패합니다. VisualStudio 2010에서 컴파일하면 아무데도 실패하지 않습니다. VisualStudio2005에서 손가락을 가리킬 수도 있지만 location-sensitivve 문제는 의심 스럽지만 VS 2005 및 VS 2010의 다른 최적화 도구는 코드를 약간 다른 위치에 배치합니다.

2012 년 11 월 : 사가가 계속됩니다.우리는 꽤 낮은 속도 (수천 회 실행마다 한 번)로 다수의 XP 및 Windows 7 시스템에서이 실패를 봅니다. Suspend 활동은 대부분 순수한 계산 코드를 실행하지만 때로는 Windows로 호출하는 스레드에 적용됩니다. 쓰레드의 PC가 우리의 계산 코드에있을 때이 문제를 본 것을 기억하지 못합니다. 물론 GetContext가 나에게주지 않기 때문에 스레드가 멈 추면 스레드의 PC를 볼 수 없기 때문에 시스템 호출을 실행할 때만 문제가 발생한다는 것을 직접 확인할 수는 없습니다. 그러나 우리의 모든 시스템 호출은 한 지점을 통해 전달되며, 지금까지 그 증거는 우리가 멈출 때 그 지점이 실행된다는 것입니다. 따라서 간접적 인 증거에 따르면 시스템 호출이 해당 스레드에 의해 실행될 경우에만 스레드의 GetContext가 실패합니다. 나는 아직이 가설을 시험하기위한 비판적인 실험을 할 에너지가 없다.

+0

2010 년 11 월 "VS 2005 VS VS 2010으로 컴파일 할 때 다른 결과 가져 오기"* 이후 버전의 OS에서 정렬 제약 조건 (?)이 추가 될 수도 있습니다. http://stackoverflow.com/q/4696543/120163 –

답변

2

CriticalSection을 소유 한 스레드를 일시 중단하는 것과 관련하여 몇 가지 특별한 문제가 있습니다. 지금은 좋은 참고 문헌을 찾을 수 없지만, is one mention of it on Raymond Chen's bloganother mention on Chris Brumme's blog이 있습니다. 기본적으로 스레드가 OS 잠금 (예 : 힙 잠금, DllMain 잠금 등)에 액세스하는 동안 SuspendThread에 전화하기에 불충분하다면 정말 이상한 일이 발생합니다. 일이 발생할 수 있습니다. 이 경우에는 으로 거의 실행되지 않고 있다고 가정합니다..

Sleep(0)과 같은 프로세서 출력 후에도 GetThreadContext에 대한 호출을 다시 시도 할 수 있습니까?

+0

AFAIK를 참조하십시오. 스레드가 CriticalSection을 소유하고 있는지 여부는 중요하지 않습니다. 크레디트를 중지하면 CriticalSection을 소유하게됩니다. 일시 중지자가 해당 리소스를 사용하려고 시도하지 않는 한 다른 리소스 (예 : 동적 할당 스토리지 블록) 소유를 중단하는 것보다 더 나쁨이 없습니다. 우리는 그렇게하지 않습니다. –

+0

... 어떤 스레드가 수면 (0), 현수막 또는 현수막을하고 있다고 제안합니까? Suspender가 Sleep (0)을하는 지점을 볼 수 없으며 Suspender는 Suspendee를 자신의 편의에서 Sleep (0)으로 만들 수 없으므로 제안되는 내용을 이해할 수 없습니다. –

+0

나는 첸의 블로그를 보았다. 예, 현수교가 동일한 리소스 (동적 할당 포함)를 사용하면 교착 상태가 발생할 수 있습니다. 우리의 검사 스레드는 그것을하지 않습니다. (SuspendThread와 GetThreadContext 사이의 2 줄의 코드로 Context를 우리가 원하는대로 설정합니다. 예제 코드가 내 질문에 추가되었습니다.) 그리고 우리는 교착 상태를 보지 않고 있습니다. 오히려 GetThreadContext가 오류 5를 생성하는 것을 보았습니다. –

3

것은 나를 리히터/Nassare의 "Windows via C++ 5Ed"약간의 빛을 흘릴 수있는 인용 보자 :

DWORD의 SuspendThread로 (핸들 hThread을);

어떤 스레드도이 기능을 다른 스레드를 일시 중단 할 수 있습니다 (사용자가 스레드의 핸들을 가지고있는 한). 스레드는 자체를 일시 중단 할 수 있지만 자체를 다시 시작할 수는 없다는 말은하지 않고 이됩니다 (그러나 어쨌든 라고 말합니다). ResumeThread와 마찬가지로 SuspendThread는 스레드의 이전 일시 중단 수를 으로 반환합니다. 스레드는 MAXIMUM_SUSPEND_COUNT 번 (WinNT.h에서 으로 정의 됨)까지 일시 중단 될 수 있습니다. SuspendThread는 커널 모드 실행과 관련하여 과 비동기이지만 스레드가 다시 시작될 때까지 사용자 모드 실행이 발생하지 않습니다. 당신이 그것을 중단 을 시도 할 때 스레드가 일을 할 수있는 무엇 아무 생각이 있기 때문에, SuspendThread로 호출 할 때

실제 생활에서 응용 프로그램주의 해야합니다. 예를 들어 스레드가 힙에서 메모리를 할당하려고 시도하면 스레드는 에 힙을 잠급니다. 다른 스레드가 힙에 액세스하려고 시도하면 첫 번째 스레드가 다시 시작될 때까지 실행이 중지됩니다. 대상 스레드가 정확히 을 알고 (또는 이 일을 할 수 있음)하고 스레드를 일시 중단으로 인한 문제 나 교착 상태를 방지하기 위해 극단적 인 조치를 취할 경우에만 SuspendThread로는 안전합니다.

...

실제로 Windows는 스레드의 커널 개체를보고 현재 CPU 레지스터 집합을 가져옵니다. 이 을 수행하려면, 당신은 단순히 GetThreadContext 전화 :

BOOL GetThreadContext을 (PCONTEXT pContext을 hThread 핸들);

은 다시하고 싶지 등록하는 나타내는 일부 플래그 (구조의 ContextFlags 멤버를) 초기화, 단지 CONTEXT 구조를 할당,이 함수를 호출하고, GetThreadContext에 구조의 주소 를 전달합니다. 그러면 함수가 요청한 멤버 을 채 웁니다.

당신은 GetThreadContext를 호출하기 전에, SuspendThread로 전화한다 그렇지 않으면 스레드가 예약되고 스레드의 컨텍스트가 과 다를 수 있습니다. 스레드 에는 실제로 사용자 모드 과 커널 모드의 두 가지 컨텍스트가 있습니다. GetThreadContext는 스레드의 사용자 모드 컨텍스트 만 반환 할 수 있습니다. SuspendThread를 으로 호출하면 스레드가 중지되지만 해당 스레드는 커널 모드에서 현재 실행 중입니다. SuspendThread가 실제로 스레드를 아직 일시 중단했지만 의 사용자 모드 컨텍스트가 안정적입니다. 그러나 스레드는 다시 시작될 때까지 사용자 모드 코드를 더 이상 실행할 수 없으므로 스레드 을 안전하게 중단하고 GetThreadContext를 으로 간주 할 수 있습니다.

내 생각에 스레드가 커널 모드에 있고 커널이 스레드 컨텍스트 블록을 잠그고있는 동안 SuspendThread를 방금 호출하면 GetThreadContext가 실패 할 수 있습니다.

멀티 코어 시스템에서 한 코어가 사용자 모드가 일시 중단 된 스레드의 커널 모드 실행을 처리 중이며 다른 코어가 GetThreadContext를 호출 할 때 스레드의 CONTEXT 구조를 계속 잠금 상태로 유지합니다. 이 동작이 문서화되지 않기 때문에

, 나는 마이크로 소프트에 문의하시기 바랍니다.

0

아마도 스레드 안전 문제 일 수 있습니다. hComputeThread 구조체가 당신 밑에서 변경되지 않는다고 확신합니까? 일시 중지를 호출 할 때 스레드가 종료되었을 수 있습니까? 이로 인해 일시 중지가 성공할 수 있지만 컨텍스트 가져 오기를 호출하면 처리가 취소되고 핸들이 유효하지 않습니다.

+0

아무 응답도 튀는 것을 보이지 않는다. 나는 적어도 그럴듯한 설명을 해줄 점들을 당신에게 건네고 있습니다. 실제로이 문제가 있다고 생각하지 않지만 GetHandle이 불평하는지 확인하기 위해 "GetHandleProperties"검사를 추가하고 있습니다. –

+0

(Nov 2010) 2 달 후 GetHandleProperties check-for-null-handle을 추가했습니다. 트리거하지 마십시오. –

2

오래된 문제가 여전히 당신을보고 좋은은 다른 2 년 이상 문제가 발생한 후 상태 변경 사항으로 업데이트 상태로 유지.

http://social.msdn.microsoft.com/Forums/en/windowscompatibility/thread/1558e9ca-8180-4633-a349-534e8d51cf3a

하게하는 WoW64에서 GetThreadContext에서 오히려 중요한 버그가 있습니다 :

문제의 원인은하면 WoW64의 x64 버전의 번역 층에서이 문제로 당 있다는 것입니다 많은 상황에서 사용할 수 없도록하는 오래된 내용을 반환합니다. 내용은 사용자 모드로 저장됩니다. 따라서 값이 null이 아닌 것으로 생각하지만 부실 내용에서는 여전히 null입니다.

이것은 새로운 OS에서는 실패하지만 이전 OS에서는 실패한 이유이기 때문에 Windows 7 32 비트 OS에서 실행 해보십시오.

Visual Studio 2010/2012를 기반으로 구축 된 솔루션에서이 버그가 자주 발생하지 않는 이유는 컴파일러가 문제의 대부분을 완화하고있는 것으로 보입니다.이 때문에 생성 된 IL을 검사해야합니다. 2005 년과 2010 년의 차이점을 확인하십시오. 예를 들어 프로젝트가 최적화없이 구축 된 경우 문제가 발생합니까?

마지막으로, 몇 가지 추가 읽기 : 같은 또는 중요 섹션이하는으로 이어질 수있는 뮤텍스로 동기화 개체를 소유 한 스레드에 SuspendThread로를 호출

http://www.nynaeve.net/?p=129

+0

예,이 문제 이외에도 *이 문제가 발생했습니다.이 문제의 증상은 GetThreadContext가 기본적으로 컨텍스트를 얻지 못했다는 오류를 반환한다는 것입니다. 짜증나지만 치명적이지 않습니다. Zach가 발견 한 문제는 Wow64에서 GetThreadContext가 당신이 얻는 컨텍스트에 대해 당신에게 거짓말을한다는 것입니다; 너는 단지 잘못된 값을 얻는다. 응용 프로그램이 중단 된 스레드의 PC를 발견하는 데 의존하는 경우 치명적입니다. 기술 범죄와 비슷한 수준입니다. 어떤 OS 디자이너라도 스레드 상태를 얻을 수 없다고 말하면 공포에 처할 것입니다. –

+0

뉴스 : 이제 컨텍스트를 요청할 때와 변경 할 때 안정적으로 제어 할 수 있으며 여러 시스템에서 수천 번의 테스트를 실행할 수 있습니다. WinXP-64에서는 GetThreadContext의 동작이 잘된 것처럼 보입니다. WinXP-64에 대한 MS의 지원이 중단되었습니다. 실제로 작동합니다. 64 비트 Windows Vista 시스템이 없습니다. 여러 Windows 7 시스템은 수천 번의 시도가있을 때마다 한 번씩 실패합니다. 즉,이 호출을 사용하는 장시간 실행되는 프로그램이 예기치 않게 한 번씩 죽는 것을 의미합니다. Windows 8에는 내가 설치 한 픽스가 있다고 주장되지만 작동하지 않는 것으로 보입니다. –

+0

@Ira Baxter : 짧은 수면 시간에 루프를 돌면서 GetThreadContext 호출이 성공할 때까지 다시 시도하거나 0이 아닌 레지스터를 반환 할 때까지 다시 시도하는 것과 같은 해결 방법이 있는지 알고 있습니까? 필자의 경우 디버거에서 스택 추적을 생성하기 위해이 작업을 수행해야 할 때 코드가 시간이 중요하지 않습니다. –

0

교착 상태 호출중인 스레드가 일시 중단 된 스레드가 소유 한 동기화 개체를 얻으려고하는 경우. - MSDN

+0

네, 그건 고전적이고 명백합니다. 그건 문제가 아니야. 일시 중지를 수행하는 스레드가 수행하는 유일한 작업은 일시 중단 된 스레드의 상태를 검사하거나 변경하고 로컬 계산을 수행하는 것입니다. 어떠한 종류의 잠금이나 OS 호출도 없습니다. –

+1

정지 코드에서 CRT를 사용하지 않았습니까? 그렇지 않으면 데드 록이 발생할 수 있습니다. 참조 : http://blog.kalmbachnet.de/?postid=16 –

관련 문제