STA component안에서의 Long Blocking Call은 회피해야 한다. 이것은 엄밀히 말하면, Deadlock Condition은 아니다. 단지, Multiple threads가 해당 STA 안에는 존재할 수 있으며, 단지, 하나의 Thread만 처리되도록 Synchronization이 되는 구조이므로 하나의 Thread가 다른 Apartment로 Call out 하여 Call return을 기다릴 때, 그리고, 이것이 불행히도 시간이 오래 걸리는 RPC, Socket 통신과 같은 류라면, 이와 관련 없는 다른 Thread들은 starvation 현상이 발생할 수 있다. 이는 performance에 영향을 미칠 수도 있으며, User는 Hang 현상이라고도 생각할 수 있다.
이러한 경우의 Hang 상태에서 WinDbg를 통해 Thread를 확인해 보면, 간혹 아래와 같은 Callstack을 확인할 수 있으며, 언급한 것처럼, 해당 STA Component를 찾아 Long Blocking Call이 없는 지 확인해야 할 것이다.
0:018> kbL
ChildEBP RetAddr Args to Child
01ebea08 7c962124 7c82bad8 0000037c 00000000 ntdll!KiFastSystemCallRet
01ebea0c 7c82bad8 0000037c 00000000 00000000 ntdll!NtWaitForSingleObject+0xc
01ebea7c 7c82ba42 0000037c ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xac
01ebea90 774c54a7 0000037c ffffffff 01ebeb94 kernel32!WaitForSingleObject+0x12
01ebeaac 77589905 000a4c58 000d4c78 00000000 ole32!GetToSTA+0x6f
01ebeacc 77587ed7 01ebeb94 01ebec94 000bcf10 ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0xcb
01ebebac 77495349 000bcf10 01ebeca4 01ebec94 ole32!CRpcChannelBuffer::SendReceive2+0xc1
01ebec18 774952e1 000bcf10 01ebeca4 01ebec94 ole32!CAptRpcChnl::SendReceive+0xab
01ebec6c 77c8127e 000bcf10 01ebeca4 01ebec94 ole32!CCtxComChnl::SendReceive+0x113
01ebec88 77c813ca 0322b36c 01ebecd0 0600016e rpcrt4!NdrProxySendReceive+0x43
01ebf070 77c811bd 77476298 77479224 01ebf0a8 rpcrt4!NdrClientCall2+0x206
01ebf090 77bf3a12 0000001c 00000003 01ebf0ec rpcrt4!ObjectStublessClient+0x8b
01ebf0a0 77492ee6 0322b36c 01ebf0d8 00000005 rpcrt4!ObjectStubless+0xf
01ebf0ec 77493095 01eb0001 01ebf170 01ebf120 ole32!CStdMarshal::Begin_RemQIAndUnmarshal1+0xaf
01ebf10c 77492fc2 01eb0001 01ebf170 01ebf120 ole32!CStdMarshal::Begin_QueryRemoteInterfaces+0x54
01ebf154 77492f2f 01eb0001 01ebf170 01ebf168 ole32!CStdMarshal::QueryRemoteInterfaces+0x37
01ebf1a0 774a3bde 01ebf168 01ebf170 01ebf1b8 ole32!CStdIdentity::CInternalUnk::QueryMultipleInterfaces+0xda
01ebf1c4 792179c6 0586dad0 01ebf25c 01ebf240 ole32!CStdIdentity::CInternalUnk::QueryInterface+0x33
01ebf1e4 792414ed 0586dad4 01ebf25c 01ebf240 mscorsvr!SafeQueryInterface+0x36
01ebf200 7924193e 0586dad4 01ebf25c 01ebf240 mscorsvr!ComPlusWrapper::SafeQueryInterfaceRemoteAware+0x15
0:018> dd 0x000a4c58+8 l2
01ebeab0 00000ab0 000002b7c < --------- ab0는 PID, 2b7c는 TID
Component에서 UI를 handling 하고 있다면, 이는 STA에 놓아야 한다. 만일, MTA안에 놓일 경우에는 UI hang 현상이 발생할 수 있는 데, 이는 MTA기반에 Cross apartment Calling과 같은 RPC call이 있을 경우에, (이것이 근본적으로 Synchronization Call이므로,) 다른 처리는 모두 Blocking이 되며, UI thread도 예외는 아닐 것이다. 그러나, STA에 놓인다면, 이러한 현상이 발생하지 않는 다. 이유는 STA의 Mechanism에 있다. STA에서 cross apartment calling과 같은 Call out이 발생하는 경우나 동일한 Apartment에 존재하는 Multiple clients request는 Hidden Window인 OleMainThreadWndClass에 의해서 message queuing(pumping)으로 처리되어 synchronization이 되므로, cross apartment call에 대한 Call return 을 기다리더라도 Message 처리는 계속 이뤄지며, 이는 UI handling에 필요한 Message 역시 예외가 아니기 때문에 MTA와 같은 Blocking은 발생하지 않는 다. 하지만, 이러한 Mechanism에 기인하여 Cross apartment call에 의해 call out된 call return의 처리를 위해 동일한 Thread에서 re-entrancy를 허용해야만 한다.
그러므로, STA에서는 동일한 Thread내에서 re-entrance가 허용된다. 이는 또한 문제가 될 수 있다. 예를 들어, cross apartment call의 call out 중 Topmost return 이 아직 처리되지 않은 상태에서 새로운 incoming call이 발생할 경우에는 topmost return이 바라는 기존의 thread의 상태가 변경될 수 있으며, 이에 따른, 전반적인 process의 흐름에 문제가 생길 수 있다. 이러한 경우에는 topmost return이 완료될 때까지 기다리거나, 아니면, call을 reject하여 회피할 수 있는 데, 이를 위해서 IMessageFilter (참조: http://msdn.microsoft.com/en-us/library/ms693740(VS.85).aspx)를 이용하여 처리할 수도 있으며, 또한 임의의 lock이 필요하다고 생각할 지도 모른다. Message filter와 관련하여 MFC에서는 COleMessageFilter 를 제공하고 있으며 (참조: http://www.pluralsight.com/articlecontent/cpprep1098.htm) 다만, 대표적인 STA Component를 개발해 왔던 VB6에서는 지원하지 않는 다는 것이 안타깝다.
마지막으로 Cross threads Call을 위한 Marshalling Call은 locking mechanism에 비해서 매우 expensive하다.
결국, 이러한 것들은 개발자들로 하여금 STA보다는 MTA의 사용을 부추기는 지도 모르지만 MTA가 적용된 Application에서의 복잡한 locking 구조에 의한 Deadlock 현상 등은 STA의 편리함에 이끌릴지도 모르겠다.
'COM, ATL' 카테고리의 다른 글
COM 기본 개념 ~~ 정리해 보자 (0) | 2008.08.08 |
---|---|
Process/Thread/Apartment (0) | 2008.08.02 |
How to Use IMessageFilter (1) | 2008.08.02 |
Apartment Types (0) | 2008.07.30 |
COM Message Filters (0) | 2008.07.30 |
TLS(Thread Local Storage) (0) | 2008.07.30 |
Safe Initialization and Scripting for ActiveX Controls (0) | 2008.07.29 |