怪異的COM 執行緒模型
COM的本質是C/S,考慮執行緒安全的時候,也可以分別從Client和Server的角度考慮。從Client角度看,是如何安全的呼叫共享的Server;反之從Server角度看,是如何安全的對多執行緒的呼叫提供服務。以C++的角度看,Server就是一個C++類的例項,COM不過是很多機制幫助Client如何建立In-Process/Out Process的合適的C++例項。並在Out-Process的情況下,提供合適的Proxy/Stub來完成inter-process的呼叫。
[@more@]Proxy/Stub的實質是RPC/IPC,具體實現上則依賴於Windows 的MessageQ。之所以依賴於MSGQ,是因為MSGQ獨特而齷齪的非標準化設計。在Linux/Unix系統上,當要等待多個外部事件,就是去select多個對應的fd。Windows也提供select函式的支援,但是Windows MSGQ並不是一個可以被select的fd可以代替的,至少微軟公開的API不容許這樣的使用。RPC的介面能提供一個被select的fd嗎?不知道,應該不能。Windows的MessageQ,並不是一個被公開細節的Windows技術。對於擁有UI的thread,要麼在等待MSGQ新訊息,要麼在處理訊息,MSGQ成為驅動其運轉的基礎。外部非同步的事件,一定要轉換為一個Windows訊息,並放在MSGQ上面才能被本執行緒相應。MFC非同步Socket就是這樣一個例子,所有的Socket事件實際上在另外一個執行緒裡面被轉換為一個Windows Message訊息後被送到UI執行緒上(建立Socket的那個UI執行緒)。
對於擁有UI的thread,InterProcess的COM呼叫通訊由RPC完成;Client或者Server與COM子系統之間則是由MSQ介面完成。Client呼叫InterProcess的Interface的函式,即呼叫Proxy對應的函式,Proxy轉換呼叫為RPC呼叫,RPC到Server後,被轉換為一個Windows Message,Server在MSGQ裡面取訊息,處理訊息,並呼叫實際Interface的函式。返回的過程也大致相同,也即InterProcess用RPC/IPC來完成。傳送方的請求(或者返回),在本地被轉換為一個RPC,在對端RPC被轉換為一個Windows訊息,插入到對端的訊息佇列,當訊息佇列訊息被處理時,請求就被執行或者返回完成。Apartment/STA/MTA概念的引入,是要使用者在不瞭解MSGQ細節的情況下理解如何設計執行緒安全的COM Client和Server。
單個執行緒呼叫一個C++物件,當然是執行緒安全的(除非C++物件本來封裝了多個執行緒)。這對應著一個Interface在僅僅在其被建立的執行緒上呼叫。
對於DLL.COM來說,多個執行緒同時呼叫一個C++物件,當然是要考慮執行緒的安全問題(除非C++物件是完全可重入的,無狀態的)。要解決這樣的問題,方法有二。1)STA,從Client角度,讓多個執行緒的呼叫序列化是一個辦法。簡單來說,當非COM物件建立者執行緒需要呼叫這個物件的Interface時候,就給建立者執行緒發個訊息,因為建立者執行緒上對訊息處理是序列的,所以並行的呼叫被序列化。CoMarshalInterThreadInterfaceInStream/ CoGetInterfaceAndReleaseStream 這兩個函式就是為這樣的序列化做準備的。這兩個函式實際上實際上要在兩個執行緒之間建立基於RPC/IPC的Proxy/Stub關係。呼叫完成後,誇執行緒的Interface呼叫,實際上和跨Process的呼叫沒有區別了。2)MTA,從Server的角度,如果不是可重入無狀態的,那麼需要對設計上使用同步機制,保證併發被呼叫的執行緒安全。
對於EXE.COM來說,有兩種情況,即EXE.COM是否支援被併發的呼叫。如果支援,那麼Client這邊,怎麼呼叫都沒事。如果不支援,那麼就在EXE.COM的訊息佇列裡面序列化Client的併發呼叫,也就沒事了。這個做法和DLL.COM在Client側序列化呼叫是一致的。
總之一句話,要麼序列化呼叫,要麼支援被併發呼叫。
N年前,就看到這個話題,一直鬧不明白,最近仔細看看,其實也並不複雜。感覺是微軟,故意把事情搞複雜,讓人不明白,其實是想為自己垃圾的MSGQ設計遮羞罷了。如果能夠理解齷齪的MSGQ,也就見怪不怪了。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/21398729/viewspace-1020719/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- COM套間和執行緒模型.執行緒模型
- 泛說 "COM執行緒模型" (轉)執行緒模型
- COM元件的多執行緒測試-Apartment模型 (轉)元件執行緒模型
- 執行緒模型執行緒模型
- js中自執行函式的怪異行為研究JS函式
- Redis的執行緒模型Redis執行緒模型
- Dubbo的執行緒模型執行緒模型
- memcache的執行緒模型執行緒模型
- 標準盒模型和怪異盒模型模型
- Dubbo執行緒模型執行緒模型
- WPF執行緒模型執行緒模型
- redis執行緒模型Redis執行緒模型
- COM元件的多執行緒測試-Apartment模型(附錄) (轉)元件執行緒模型
- 程式和執行緒模型執行緒模型
- webrtc執行緒模型分析Web執行緒模型
- 理解 RxJava 執行緒模型RxJava執行緒模型
- RxJava 執行緒模型分析RxJava執行緒模型
- Netty執行緒模型Netty執行緒模型
- 03.執行緒模型執行緒模型
- Redis執行緒模型的前世今生Redis執行緒模型
- Android的程式,執行緒模型Android執行緒模型
- 聊聊執行緒技術與執行緒實現模型執行緒模型
- 執行緒池OOM異常執行緒OOM
- Node.js 的單執行緒事件驅動模型和內建的執行緒池模型Node.js執行緒事件模型
- 淺談linux執行緒模型和執行緒切換Linux執行緒模型
- js new Date怪異行為JS
- COM元件中的執行緒模式 (轉)元件執行緒模式
- 多執行緒之共享模型執行緒模型
- 淺談Netty的執行緒模型Netty執行緒模型
- 深入學習redis 的執行緒模型Redis執行緒模型
- 深入理解 RxJava 的執行緒模型RxJava執行緒模型
- 執行緒池執行模型原始碼全解析執行緒模型原始碼
- 一個執行緒罷工的詭異事件執行緒事件
- 執行緒同步的詭異:求指點執行緒
- 鴻蒙HarmonyOS實戰-Stage模型(執行緒模型)鴻蒙模型執行緒
- Redis之單執行緒 Reactor 模型Redis執行緒React模型
- Java 執行緒記憶體模型Java執行緒記憶體模型
- 【Netty】EventLoop和執行緒模型NettyOOP執行緒模型