성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <br /> <div style='font-family: 맑은 고딕, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>다른 스레드의 호출 스택 덤프 구하는 방법</div><br /> <br /> 처음 이 기능이 필요했을 때 매우 쉬울 것이라고 생각했습니다. 왜냐하면, 이미 System.Diagnostics.StackTrace 타입에서 충분한 기능을 제공하기 때문입니다.<br /> <br /> 문제는 "다른 스레드"의 콜 스택을 얻을 때 발생했습니다. StackTrace의 생성자 목록에는 이에 대한 배려도 되어 있는데, 실제로 사용해 보면... 결과는 다소 당혹스럽습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > static void Main(string[] args) { Thread newThread = new Thread(Run); newThread.Start(); System.Diagnostics.StackTrace trace = <b style='COLOR: blue'>new System.Diagnostics.StackTrace(newThread, false);</b> } private static void Run() { Thread.Sleep(1000 * 10); } </pre> <br /> 위의 코드를 실행해 보면, 다음과 같은 예외를 만나게 됩니다.<br /> <br /> <SPAN style='BACKGROUND-COLOR: #ccffcc; FONT-STYLE: italic; MARGIN: 10px 0px 10px 10px; WIDTH: 800px; FONT-FAMILY: 맑은 고딕, Consolas, Verdana; COLOR: #005555'><br /> <b style='COLOR: blue'>Unhandled Exception: System.Threading.ThreadStateException: Thread in invalid state.</b><br /> at System.Diagnostics.StackTrace.GetStackFramesInternal(StackFrameHelper sfh, Int32 iSkip, Exception e)<br /> at System.Diagnostics.StackTrace.CaptureStackTrace(Int32 iSkip, Boolean fNeedFileInfo, Thread targetThread, Exception e)<br /> at System.Diagnostics.StackTrace..ctor(Thread targetThread, Boolean needFileInfo)<br /> at ConsoleApplication1.Program.Main(String[] args) in C:\temp\...\Program.cs:line 21<br /> </span><br /><br /> <br /> 닷넷 소스 코드 디버깅을 이용해 보면, 다음의 라인에서 오류가 나는 것을 확인할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > [MethodImplAttribute(MethodImplOptions.InternalCall)] internal static extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, Exception e); private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread, Exception e) { m_iMethodsToSkip += iSkip; StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread); <b style='COLOR: blue'>GetStackFramesInternal (StackF, 0, e); // 예외 발생</b> // ... [생략]... } </pre> <br /> MethodImplOptions.InternalCall로 정의된 메서드라서 더 이상 추적해 볼 여지가 없습니다. 이제 ^^ 구글로 넘어가 봐야죠.<br /> <br /> 다행히, 이와 관련해서 "Rotor" 소스 코드를 찾을 수가 있었습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Rotor Source code ; http://www.123aspx.com/rotor/RotorSrc.aspx?rot=42047 ; <a target='tab' href='https://github.com/SSCLI/sscli20_20060311/blob/master/clr/src/bcl/system/diagnostics/stacktrace.cs'>https://github.com/SSCLI/sscli20_20060311/blob/master/clr/src/bcl/system/diagnostics/stacktrace.cs</a> ; <a target='tab' href='https://github.com/dotnet/coreclr/blob/release/2.2/src/vm/debugdebugger.cpp#L327-L800'>https://github.com/dotnet/coreclr/blob/release/2.2/src/vm/debugdebugger.cpp#L327-L800</a> </pre> <br /> 중간에 보면, 다음과 같은 코드가 확인됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > public StackTrace(Thread targetThread, bool needFileInfo) { m_iNumOfFrames = 0; m_iMethodsToSkip = 0; if (targetThread != null) { if (targetThread != Thread.CurrentThread) { if (((<b style='COLOR: blue'>targetThread.ThreadState & System.Threading.ThreadState.Suspended) != 0</b>) && ((targetThread.ThreadState & System.Threading.ThreadState.SuspendRequested) != 0) && (<b style='COLOR: blue'>targetThread.ThreadState != System.Threading.ThreadState.Stopped</b>) && (targetThread.ThreadState != System.Threading.ThreadState.Unstarted)) { throw new ThreadStateException ( Environment.GetResourceString("ThreadState_NeedSuspended")); } } else targetThread = null; } CaptureStackTrace (METHODS_TO_SKIP, needFileInfo, targetThread, null); } </pre> <br /> 오호... 그러니까, "실행 상태"에 있다면 콜 스택을 얻을 수 없다는 것이군요. 그래서, 최초의 StackTrace 코드를 다음과 같이 수정해 보았습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > static void Main(string[] args) { Thread newThread = new Thread(Run); newThread.Start(); <b style='COLOR: blue'>newThread.Suspend();</b> System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace(newThread, false); <b style='COLOR: blue'>newThread.Resume();</b> Console.WriteLine(trace.ToString()); } </pre> <br /> 와~~~ ^^ 이제 예외가 발생하지 않습니다. 하지만! 출력 결과가 다소 실망스럽습니다.<br /> <br /> <SPAN style='BACKGROUND-COLOR: #ccffcc; FONT-STYLE: italic; MARGIN: 10px 0px 10px 10px; WIDTH: 800px; FONT-FAMILY: 맑은 고딕, Consolas, Verdana; COLOR: #005555'><br /> <b style='COLOR: blue'>at ConsoleApplication1.Program.Run()</b><br /> at System.Threading.ThreadHelper.ThreadStart_Context(Object state)<br /> at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)<br /> at System.Threading.ThreadHelper.ThreadStart()<br /> </span><br /><br /> <br /> 달랑, Run 메서드 프레임 하나.<br /> 이상하다 싶어서 중간에 newThread.Sleep(3000);을 한 번 더 주고 나니 정상적으로 아래와 같이 콜 스택이 출력되었습니다. (즉, 위의 콜 스택 출력 결과는 너무 빨리 시도를 했기 때문에 발생한 것으로 그것 자체도 정상적인 출력이었습니다.)<br /> <br /> <SPAN style='BACKGROUND-COLOR: #ccffcc; FONT-STYLE: italic; MARGIN: 10px 0px 10px 10px; WIDTH: 800px; FONT-FAMILY: 맑은 고딕, Consolas, Verdana; COLOR: #005555'><br /> <b style='COLOR: blue'>at System.Threading.Thread.SleepInternal(Int32 millisecondsTimeout)<br /> at System.Threading.Thread.Sleep(Int32 millisecondsTimeout)</b><br /> at ConsoleApplication1.Program.Run()<br /> at System.Threading.ThreadHelper.ThreadStart_Context(Object state)<br /> at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)<br /> at System.Threading.ThreadHelper.ThreadStart()</span><br /> <br /><br /> <br /> 이 외에, StackTrace.ToString의 결과를 사용자 정의하고 싶다면 다음의 코드를 참조하시면 도움이 되겠습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > How do I make a thread dump in .NET ? (a la JVM thread dumps) ; <a target='_tab' href='http://stackoverflow.com/questions/190236/how-do-i-make-a-thread-dump-in-net-a-la-jvm-thread-dumps'>http://stackoverflow.com/questions/190236/how-do-i-make-a-thread-dump-in-net-a-la-jvm-thread-dumps</a> </pre> <br /> 코드가 아닌, 툴을 이용하고 싶다면 다음의 방법이 좋겠고.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > .NET production debugging 101 ; <a target='_tab' href='http://www.tomergabel.com/NETProductionDebugging101.aspx'>http://www.tomergabel.com/NETProductionDebugging101.aspx</a> </pre> <br /> 혹시나, StackTrace를 이용하여 부모 메서드에 따라 동작을 다르게 만들고 싶다면 다음과 같은 함정을 주의하시기 바랍니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; width: 800px; background-color: #fbedbb; overflow-x: scroll; font-family: Consolas, Verdana;' > Caveats about System.Diagnostics.StackTrace ; <a target='_tab' href='https://learn.microsoft.com/en-us/archive/blogs/jmstall/caveats-about-system-diagnostics-stacktrace'>https://learn.microsoft.com/en-us/archive/blogs/jmstall/caveats-about-system-diagnostics-stacktrace</a> </pre> <br /> <a target='_tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=495&boardid=331301885'>첨부된 파일은 위의 코드를 포함하고 있는 (VS 2010 beta2)프로젝트</a>입니다.<br /> <br /> 끝!<br /> <br /> <br /><br /><hr /><span style='color: Maroon'>[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1388
(왼쪽의 숫자를 입력해야 합니다.)