簡體   English   中英

傳統的VB6 COM + DLL調用本機Win32 DLL - 與STA的線程問題?

[英]Legacy VB6 COM+ DLL calling into native Win32 DLL — threading issues with STA?

看看像MT一樣的第一眼看到的東西,但我試圖詳細了解COM +使用的STA模型。

實際上,我有一個用VB6編寫的遺留COM +組件,它調用用C ++編寫的本機(即非COM)Win32 DLL。

有一些間歇性(並且不可能在測試中重現)問題,我添加了一些調試代碼來找出發生了什么,並發現當問題發生時,我在文件中交錯了日志消息 - 所以它暗示了DLL被兩個線程同時調用。

現在,日志記錄轉到基於_getpid()和GetCurrentThreadId()的每線程文件,所以看起來當調用C ++ DLL中的代碼時,它會在同一個線程上同時被調用兩次。 我對STA的理解表明,可能就是這種情況,因為COM將對象的各個實例編組到一個線程上,並隨意恢復執行。

不幸的是,我不確定從哪里開始。 我正在讀我應該在DllMain()中調用CoInitialiseEx()告訴COM這是一個STA DLL,但其他地方說這只對COM DLL有效,並且在本機DLL中不會有任何影響。 唯一的另一個選擇是將DLL的一部分包裝為關鍵部分以序列化訪問(獲取下巴上的任何性能命中)。

我可以嘗試重做DLL,但是沒有共享狀態或全局變量 - 一切都在局部變量中所以理論上每個調用應該得到自己的堆棧,但我想知道STA模型是否基本上對此有一些奇怪的影響並在與另一個調用相同的入口點重新進入已加載的DLL。 不幸的是,我不知道如何證明或測試這個理論。

問題基本上是:

  1. 當STA COM +組件調用本機DLL時,STA模型中沒有任何內容可以防止活動“線程”被掛起並且控制在DLL調用過程中被傳遞給另一個“線程”?
  2. CoInitialiseEx()是解決這個問題的正確方法嗎?
  3. 如果(1)或(2)都不是“好的”假設,那么會發生什么?

在公寓線程COM服務器中,COM類的每個實例都保證由單個線程訪問。 這意味着該實例是線程安全的。 但是,可以使用不同的線程同時創建許多實例。 現在,就COM服務器而言,您的本機DLL不必執行任何特殊操作。 想想每個可執行文件使用的kernel32.dll - 它是否在COM服務器使用時初始化COM?

從DLL的角度來看,您必須確保線程安全,因為不同的實例可以同時調用您。 在這種情況下,STA不會保護您。 既然你說你沒有使用任何全局變量,我只能假設問題出現在其他地方,並恰好在似乎指向COM內容的環境中顯示。 你確定你沒有一些普通的舊C ++內存問題嗎?

我懷疑你的問題是在被調用的DLL內部的某個地方,它對另一個公寓(同一進程中的另一個線程,或MTA中的對象,或完全是另一個進程)進行了外向COM調用。 COM允許等待出站呼叫結果的STA線程接收另一個入站呼叫,遞歸處理它。 它僅用於相同對象之間的持續對話 - 即A調用B,B調用A返回,A調用B再返回 - 但如果您已發出指向多個客戶端的接口指針或客戶端,則可以接收來自其他對象的調用已共享指向另一個客戶端的接口指針。 通常,將單線程對象的接口指針分發給多個客戶端線程是一個壞主意,因為它們只需要彼此等待。 每個線程創建一個工作對象。

COM無法在任何線程上隨意掛起和恢復執行 - STA線程上的新傳入呼叫只能通過消息泵到達。 當'阻塞'等待響應時,STA線程實際上正在泵送消息,使用消息過濾器(請參閱IMessageFilter)檢查是否應該處理該消息。 但是,消息處理程序不能進行新的傳出調用 - 如果它們執行COM將返回RPC_E_CANTCALLOUT_INEXTERNALCALL錯誤(“在消息過濾器內部調用是非法的。”)

如果在本機DLL中的任何位置都有消息泵(GetMessage / DispatchMessage),則可能會出現類似問題。 我在接口程序中遇到了VB的DoEvents問題。

CoInitializeEx只能由線程的創建者調用,因為只有他們知道他們的消息泵行為才會是什么。 如果您嘗試在DllMain中調用它,它可能會失敗,因為您的本機DLL是在響應COM調用時被調用的,因此調用者必須最終已經在線程上調用CoInitializeEx才能進行調用。 對於新創建的線程,在DLL_THREAD_ATTACH通知中執行此操作可能會表面上工作,但如果COM阻塞它應該泵送,則會導致程序出現故障,反之亦然。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM