성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>windbg - 풀 덤프에서 .NET 스레드의 상태를 알아내는 방법</h1> <p> System.Threading.Thread 타입은 Suspend와 Resume 메서드를 제공해 스레드의 일시 정지/재개를 할 수 있습니다.<br /> <br /> 그렇다면 그 상태를 어떻게 풀 덤프에서 알 수 있을까요? 어렵게 생각하지 말고 ^^ 그냥 간단하게 상황을 재현해 테스트해보면 됩니다. 이를 위해 다음과 같이 CPU를 소비하는 코드를 만들어 Running 상태의 스레드를 재현하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > while (true) { for (int i = 0; i < Int32.MaxValue; i ++) { sum += i; } System.Diagnostics.Trace.WriteLine(sum.ToString()); } </pre> <br /> 실행 후 풀 덤프를 떠서 windbg로 로딩합니다.<br /> <br /> 우선, CPU를 소비한 스레드를 파악하고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!runaway</span> User Mode Time Thread Time <span style='color: blue; font-weight: bold'>6:8684 0 days 0:00:15.375</span> 0:33cc 0 days 0:00:00.031 5:77bc 0 days 0:00:00.015 4:6cbc 0 days 0:00:00.000 3:44bc 0 days 0:00:00.000 2:5960 0 days 0:00:00.000 1:723c 0 days 0:00:00.000 </pre> <br /> 이에 대한 스레드 정보를 sos로 확인합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>.loadby sos clr</span> 0:000> <span style='color: blue; font-weight: bold'>!threads</span> ThreadCount: 3 UnstartedThread: 0 BackgroundThread: 1 PendingThread: 0 DeadThread: 0 Hosted Runtime: no Lock ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception 0 1 33cc 0000000000a24380 2a020 Preemptive 00000000029A7E18:00000000029A7FD0 0000000000a06000 1 MTA 5 2 77bc 0000000000a4f6d0 2b220 Preemptive 0000000000000000:0000000000000000 0000000000a06000 0 MTA (Finalizer) <span style='color: blue; font-weight: bold'>6 3 8684 0000000000a80d10 2b020</span> Cooperative 00000000029D5228:00000000029D5FD0 0000000000a06000 0 MTA </pre> <br /> 6번 스레드이고, State 값이 2b020으로 나옵니다. 따라서 !ThreadState로 조회하면 스레드의 현재 상태를 알 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!ThreadState 2b020</span> Legal to Join CLR Owns CoInitialized In Multi Threaded Apartment Fully initialized </pre> <br /> 딱히 Running이라는 단어는 없는데 그냥 저 상태 값이면 Running이라고 보면 됩니다.<br /> <br /> 그렇다면 Thread.Suspend 했을 때는 어떨까요? 닷넷에서 호출 후 역시 덤프를 뜨고 확인해 보면 다음과 같은 출력값이 나옵니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:000> <span style='color: blue; font-weight: bold'>!ThreadState ab024</span> <span style='color: blue; font-weight: bold'>User Suspend Pending</span> Legal to Join CLR Owns CoInitialized In Multi Threaded Apartment Fully initialized <span style='color: blue; font-weight: bold'>Sync Suspended</span> </pre> <br /> 또는, 다른 스레드에 의해 점유된 lock을 획득하기 위해 Monitor.Enter로 진입한 스레드의 상태는 다음과 같습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:382> <span style='color: blue; font-weight: bold'>!ThreadState 3009220</span> Legal to Join Background CLR Owns In Multi Threaded Apartment Thread Pool Worker Thread <span style='color: blue; font-weight: bold'>Interruptible</span> </pre> <br /> 참고로, ThreadState 값은 주소가 아닌 Enum Flags 값이기 때문에, 프로세스 실행 단위로 변하지 않으므로 2b020, ab024가 저런 상태이구나... 라고 외워도 무방합니다. 각각의 플래그 값은 다음의 소스 코드에서 찾아볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > crummel/dotnet_coreclr ; <a target='tab' href='https://github.com/crummel/dotnet_coreclr/blob/master/src/ToolBox/SOS/Strike/strike.cpp'>https://github.com/crummel/dotnet_coreclr/blob/master/src/ToolBox/SOS/Strike/strike.cpp</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > static const struct ThreadStateTable ThreadStates[] = { {0x1, "Thread Abort Requested"}, {0x2, "GC Suspend Pending"}, {0x4, "User Suspend Pending"}, {0x8, "Debug Suspend Pending"}, {0x10, "GC On Transitions"}, {0x20, "Legal to Join"}, {0x40, "Yield Requested"}, {0x80, "Hijacked by the GC"}, {0x100, "Blocking GC for Stack Overflow"}, {0x200, "Background"}, {0x400, "Unstarted"}, {0x800, "Dead"}, {0x1000, "CLR Owns"}, {0x2000, "CoInitialized"}, {0x4000, "In Single Threaded Apartment"}, {0x8000, "In Multi Threaded Apartment"}, {0x10000, "Reported Dead"}, {0x20000, "Fully initialized"}, {0x40000, "Task Reset"}, {0x80000, "Sync Suspended"}, {0x100000, "Debug Will Sync"}, {0x200000, "Stack Crawl Needed"}, {0x400000, "Suspend Unstarted"}, {0x800000, "Aborted"}, {0x1000000, "Thread Pool Worker Thread"}, {0x2000000, "Interruptible"}, {0x4000000, "Interrupted"}, {0x8000000, "Completion Port Thread"}, {0x10000000, "Abort Initiated"}, {0x20000000, "Finalized"}, {0x40000000, "Failed to Start"}, {0x80000000, "Detached"}, }; </pre> <br /> <hr style='width: 50%' /><br /> <br /> 그런데, 혹시 System.Threading.Thread의 ThreadState 값은 어떨까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ThreadState Enumeration ; <a target='tab' href='https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadstate'>https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadstate</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [ComVisible(true)] [Flags] public enum ThreadState { Running = 0, StopRequested = 1, SuspendRequested = 2, Background = 4, Unstarted = 8, Stopped = 16, WaitSleepJoin = 32, Suspended = 64, AbortRequested = 128, Aborted = 256 } </pre> <br /> 값이 다른 걸로 봐서는 아마도 windbg의 ThreadState와는 다른 기준을 갖는 듯합니다.<br /> <br /> 이를 알기 위해서는 결국 해당 스레드를 실행하고 있는 System.Threading.Thread 객체를 알아내야 합니다. 현재, 이에 대한 직접적인 방법은 없지만 !dumpheap을 통해 찾아들어갈 여지는 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > WinDbg/SOS: How to correlate managed threads from !threads command with System.Threading.Thread instances ; <a target='tab' href='https://stackoverflow.com/questions/4616584/windbg-sos-how-to-correlate-managed-threads-from-threads-command-with-system-t'>https://stackoverflow.com/questions/4616584/windbg-sos-how-to-correlate-managed-threads-from-threads-command-with-system-t</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:006> <span style='color: blue; font-weight: bold'>!dumpheap -type System.Threading.Thread</span> Address MT Size 00000000029a12c8 00007fff2f296eb8 160 00000000029a1368 00007fff2f296eb8 160 00000000029a3f00 00007fff2f2a2b20 64 <span style='color: blue; font-weight: bold'>00000000029a3f40 00007fff2f297d18 96</span> 00000000029a3fa0 00007fff2f285618 40 00000000029a4008 00007fff2f2a2b20 64 <span style='color: blue; font-weight: bold'>00000000029a4048 00007fff2f297d18 96</span> Statistics: MT Count TotalSize Class Name 00007fff2f285618 1 40 System.Threading.ThreadHelper 00007fff2f2a2b20 2 128 System.Threading.ThreadStart <span style='color: blue; font-weight: bold'>00007fff2f297d18 2 192 System.Threading.Thread</span> 00007fff2f296eb8 2 320 System.Threading.ThreadAbortException Total 7 objects </pre> <br /> 이 중에서 Address의 값으로 덤프를 해 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:006> <span style='color: blue; font-weight: bold'>!DumpObj /d 00000000029a3f40</span> Name: System.Threading.Thread MethodTable: 00007fff2f297d18 EEClass: 00007fff2ec5ace0 Size: 96(0x60) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll Fields: MT Field Offset Type VT Attr Value Name 00007fff2f22c378 40018ef 8 ....Contexts.Context 0 instance 00000000029d2ae0 m_Context 00007fff2f2aec38 40018f0 10 ....ExecutionContext 0 instance 0000000000000000 m_ExecutionContext 00007fff2f296938 40018f1 18 System.String 0 instance 00000000029a3e60 m_Name 00007fff2f298d98 40018f2 20 System.Delegate 0 instance 0000000000000000 m_Delegate 00007fff2f29b5f0 40018f3 28 ...ation.CultureInfo 0 instance 0000000000000000 m_CurrentCulture 00007fff2f29b5f0 40018f4 30 ...ation.CultureInfo 0 instance 0000000000000000 m_CurrentUICulture 00007fff2f296f18 40018f5 38 System.Object 0 instance 0000000000000000 m_ThreadStartArg 00007fff2f2afbb0 40018f6 40 System.IntPtr 1 instance <span style='color: blue; font-weight: bold'>a80d10 DONT_USE_InternalThread</span> 00007fff2f299278 40018f7 48 System.Int32 1 instance 2 m_Priority 00007fff2f299278 40018f8 4c System.Int32 1 instance <span style='color: blue; font-weight: bold'>3 m_ManagedThreadId</span> 00007fff2f2a1f18 40018f9 50 System.Boolean 1 instance 1 m_ExecutionContextBelongsToOuterScope 00007fff2f290448 40018fa db0 ...LocalDataStoreMgr 0 shared static s_LocalDataStoreMgr >> Domain:Value 0000000000a06000:NotInit << 00007fff2fdb4570 40018fc db8 ...eInfo, mscorlib]] 0 shared static s_asyncLocalCurrentCulture >> Domain:Value 0000000000a06000:NotInit << 00007fff2fdb4570 40018fd dc0 ...eInfo, mscorlib]] 0 shared static s_asyncLocalCurrentUICulture >> Domain:Value 0000000000a06000:NotInit << 00007fff2f28f3f8 40018fb 18 ...alDataStoreHolder 0 shared TLstatic s_LocalDataStore >> Thread:Value << </pre> <br /> m_ManagedThreadId와 DONT_USE_InternalThread(참고 <a target='tab' href='http://www.sysnet.pe.kr/2/0/1724'>1</a>, <a target='tab' href='http://www.sysnet.pe.kr/2/0/1244'>2</a>, <a target='tab' href='http://www.sysnet.pe.kr/2/0/1388'>3</a>, <a target='tab' href='http://www.sysnet.pe.kr/2/0/1395'>4</a>, <a target='tab' href='http://www.sysnet.pe.kr/2/0/1257'>5</a>) 값을 발견할 수 있습니다. DONT_USE_InternalThread 값은 !threads 명령어로 출력된 ThreadOBJ와 값이 같습니다.<br /> <br /> 스레드가 많을 경우 일치하는 m_ManagedThreadId를 이런 식으로 하나씩 눌러가며 찾으려면 피곤해지는데요. 이를 위해 "<a target='tab' href='https://stackoverflow.com/questions/4616584/windbg-sos-how-to-correlate-managed-threads-from-threads-command-with-system-t'>WinDbg/SOS: How to correlate managed threads from !threads command with System.Threading.Thread instances</a>" 글에 좋은 매크로가 소개되어 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:006> <span style='color: blue; font-weight: bold'>.foreach ($t {!dumpheap -mt 00007fff2f297d18 -short}) { .printf " Thread Obj ${$t} and the Thread Id is %N \n",poi(${$t}+4c) }</span> </pre> <br /> 제 경우에 출력 결과는 이렇고,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Thread Obj 00000000029a3f40 and the Thread Id is 0000000100000003 Thread Obj 00000000029a4048 and the Thread Id is 0000000000000001 </pre> <br /> 따라서 1번 스레드의 System.Threading.Thread.ThreadState 값을 원한다면 다음과 같이 명령을 내리면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 0:006> <span style='color: blue; font-weight: bold'>!do 00000000029a4048</span> Name: System.Threading.Thread MethodTable: 00007fff2f297d18 EEClass: 00007fff2ec5ace0 Size: 96(0x60) bytes File: C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll Fields: MT Field Offset Type VT Attr Value Name 00007fff2f22c378 40018ef 8 ....Contexts.Context 0 instance 0000000000000000 m_Context 00007fff2f2aec38 40018f0 10 ....ExecutionContext 0 instance 0000000000000000 m_ExecutionContext 00007fff2f296938 40018f1 18 System.String 0 instance 0000000000000000 m_Name 00007fff2f298d98 40018f2 20 System.Delegate 0 instance 0000000000000000 m_Delegate 00007fff2f29b5f0 40018f3 28 ...ation.CultureInfo 0 instance 0000000000000000 m_CurrentCulture 00007fff2f29b5f0 40018f4 30 ...ation.CultureInfo 0 instance 0000000000000000 m_CurrentUICulture 00007fff2f296f18 40018f5 38 System.Object 0 instance 0000000000000000 m_ThreadStartArg 00007fff2f2afbb0 40018f6 40 System.IntPtr 1 instance <span style='color: blue; font-weight: bold'>a24380 DONT_USE_InternalThread</span> 00007fff2f299278 40018f7 48 System.Int32 1 instance 2 m_Priority 00007fff2f299278 40018f8 4c System.Int32 1 instance <span style='color: blue; font-weight: bold'>1 m_ManagedThreadId</span> 00007fff2f2a1f18 40018f9 50 System.Boolean 1 instance 0 m_ExecutionContextBelongsToOuterScope 00007fff2f290448 40018fa db0 ...LocalDataStoreMgr 0 shared static s_LocalDataStoreMgr >> Domain:Value 0000000000a06000:NotInit << 00007fff2fdb4570 40018fc db8 ...eInfo, mscorlib]] 0 shared static s_asyncLocalCurrentCulture >> Domain:Value 0000000000a06000:NotInit << 00007fff2fdb4570 40018fd dc0 ...eInfo, mscorlib]] 0 shared static s_asyncLocalCurrentUICulture >> Domain:Value 0000000000a06000:NotInit << 00007fff2f28f3f8 40018fb 18 ...alDataStoreHolder 0 shared TLstatic s_LocalDataStore >> Thread:Value << </pre> <br /> 그런데, 이상하군요. System.Threading.Thread 타입에는 ThreadState를 나타내는 필드가 없습니다. .NET Reflector 등을 통해 확인해 보면 ThreadState는 다음의 InternalCall로 연결된 것을 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > [MethodImpl(MethodImplOptions.InternalCall), SecurityCritical] private extern int GetThreadStateNative(); </pre> <br /> 그리고, CoreCLR로부터 이 정보를 찾을 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > coreclr / src / vm / comsynchronizable.cpp ; <a target='tab' href='https://github.com/dotnet/coreclr/blob/master/src/vm/comsynchronizable.cpp'>https://github.com/dotnet/coreclr/blob/master/src/vm/comsynchronizable.cpp</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FCIMPL1(INT32, ThreadNative::GetThreadState, ThreadBaseObject* pThisUNSAFE) { FCALL_CONTRACT; INT32 res = 0; Thread::ThreadState state; if (pThisUNSAFE==NULL) FCThrowRes(kNullReferenceException, W("NullReference_This")); // validate the thread. Failure here implies that the thread was finalized // and then resurrected. <span style='color: blue; font-weight: bold'>Thread *thread = pThisUNSAFE->GetInternal();</span> if (!thread) FCThrowEx(kThreadStateException, IDS_EE_THREAD_CANNOT_GET, NULL, NULL, NULL); HELPER_METHOD_FRAME_BEGIN_RET_0(); // grab a snapshot <span style='color: blue; font-weight: bold'>state = thread->GetSnapshotState();</span> <span style='color: blue; font-weight: bold'>if (state & Thread::TS_Background) res |= ThreadBackground; if (state & Thread::TS_Unstarted) res |= ThreadUnstarted; // Don't report a StopRequested if the thread has actually stopped. if (state & Thread::TS_Dead) { if (state & Thread::TS_Aborted) res |= ThreadAborted; else res |= ThreadStopped; } else { if (state & Thread::TS_AbortRequested) res |= ThreadAbortRequested; } if (state & Thread::TS_Interruptible) res |= ThreadWaitSleepJoin;</span> // CoreCLR does not support user-requested thread suspension _ASSERTE(!(state & Thread::TS_UserSuspendPending)); HELPER_METHOD_POLL(); HELPER_METHOD_FRAME_END(); return res; } FCIMPLEND </pre> <br /> 즉, 내부 thread->GetSnapshotState() 함수가 반환한 enum ThreadState 형식의 state 값을 이용해 새롭게 System.Threading.Thread의 ThreadState 값을 구성해 반환해 주는 것입니다. 그리고 enum ThreadState 값은 이전에 windbg의 ThreadState로 보았던 바로 그 내용들과 일치합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > clrmd / src / Microsoft.Diagnostics.Runtime / ClrThread.cs ; <a target='tab' href='https://github.com/Microsoft/clrmd/blob/master/src/Microsoft.Diagnostics.Runtime/ClrThread.cs'>https://github.com/Microsoft/clrmd/blob/master/src/Microsoft.Diagnostics.Runtime/ClrThread.cs</a> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > enum ThreadState { TS_Unknown = 0x00000000, // threads are initialized this way TS_StopRequested = 0x00000001, // process stop at next opportunity TS_GCSuspendPending = 0x00000002, // waiting to get to safe spot for GC TS_UserSuspendPending = 0x00000004, // user suspension at next opportunity TS_DebugSuspendPending = 0x00000008, // Is the debugger suspending threads? TS_GCOnTransitions = 0x00000010, // Force a GC on stub transitions (GCStress only) TS_LegalToJoin = 0x00000020, // Is it now legal to attempt a Join() TS_Hijacked = 0x00000080, // Return address has been hijacked TS_Background = 0x00000200, // Thread is a background thread TS_Unstarted = 0x00000400, // Thread has never been started TS_Dead = 0x00000800, // Thread is dead TS_WeOwn = 0x00001000, // Exposed object initiated this thread TS_CoInitialized = 0x00002000, // CoInitialize has been called for this thread TS_InSTA = 0x00004000, // Thread hosts an STA TS_InMTA = 0x00008000, // Thread is part of the MTA // Some bits that only have meaning for reporting the state to clients. TS_ReportDead = 0x00010000, // in WaitForOtherThreads() TS_SyncSuspended = 0x00080000, // Suspended via WaitSuspendEvent TS_DebugWillSync = 0x00100000, // Debugger will wait for this thread to sync TS_RedirectingEntryPoint = 0x00200000, // Redirecting entrypoint. Do not call managed entrypoint when set TS_SuspendUnstarted = 0x00400000, // latch a user suspension on an unstarted thread TS_ThreadPoolThread = 0x00800000, // is this a threadpool thread? TS_TPWorkerThread = 0x01000000, // is this a threadpool worker thread? (if not, it is a threadpool completionport thread) TS_Interruptible = 0x02000000, // sitting in a Sleep(), Wait(), Join() TS_Interrupted = 0x04000000, // was awakened by an interrupt APC TS_AbortRequested = 0x08000000, // same as TS_StopRequested in order to trip the thread TS_AbortInitiated = 0x10000000, // set when abort is begun TS_UserStopRequested = 0x20000000, // set when a user stop is requested. This is different from TS_StopRequested TS_GuardPageGone = 0x40000000, // stack overflow, not yet reset. TS_Detached = 0x80000000, // Thread was detached by DllMain } </pre> <br /> 정리해 보면 다음과 같은 규칙들로 정해집니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > if (TS_Background) |= ThreadBackground if (TS_Unstarted) |= ThreadUnstarted if (TS_Dead) { if (TS_Aborted) |= ThreadAborted else |= ThreadStopped } else { if (TS_AbortRequested) |= ThreadAbortRequested } if (TS_Interruptible) |= ThreadWaitSleepJoin </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1005
(왼쪽의 숫자를 입력해야 합니다.)