원문 캡처 · devblogs.microsoft.com
원문 캡처 · devblogs.microsoft.com

IInitializeSpy를 이용해 COM 아파트가 종료될 때 객체를 정리하자는 제안은 적합하지 않다. 스파이는 아파트가 아니라 스레드에 등록되므로, 콜백이 실행되는 아파트와 정리할 객체가 있는 아파트가 다를 수 있다.

CoRegisterInitializeSpy를 쓰면 등록한 스레드에서 스파이를 해제해야 한다. 따라서 원래 스레드를 기억하고 다시 그 스레드에서 코드를 실행할 방법도 마련해야 한다. 또한 CoRevokeInitializeSpy 문서는 IInitializeSpy 메서드 안에서 호출해도 현재 최상위 CoInitializeEx 또는 CoUninitialize 호출 중에 해제 효과가 나타날지는 예측할 수 없다고 명시한다. 객체를 파괴하면서 스파이를 해제해 콜백을 막으려 해도 콜백이 계속 실행될 수 있다는 뜻이다.

등록은 O(1)이지만 해제는 연결 리스트를 선형 탐색하므로 O(n)이다. 스파이가 작동하기 전에 해제되는 경우는 드물다는 가정에 따른 구현이다.

더 근본적인 문제는 스레드가 살아 있는 동안 아파트를 옮길 수 있다는 점이다. 예를 들어 중립 아파트의 객체를 호출할 때 COM은 스레드 전환 없이 호출하는 동안 스레드를 다른 아파트에서 중립 아파트로 옮겼다가 되돌릴 수 있다. 따라서 중립 아파트에 있는 마샬링할 수 없는 객체를 위해 스파이를 등록해도, 해당 스레드가 단일 스레드 아파트로서 COM을 해제할 때 PreUninitialize가 그 단일 스레드 아파트에서 실행될 수 있다. 이때 객체는 중립 아파트에 있으므로 그 콜백으로 객체를 정리할 수 없다.

멀티스레드 아파트에서도 원래 스레드가 COM을 해제했다는 이유만으로 객체를 정리하면 안 된다. 다른 스레드가 객체를 계속 유지하고 있을 수 있기 때문이다.

관련 제안은 아파트 종료 시 사용할 가짜 애자일 래퍼 논의와 IInitializeSpy 사용 제안에서 볼 수 있다.