2011-07-13 51 views
4

我想正確處理包裝在由Visual Studio生成的RCW中的傳統VFP(FoxPro)COM控件。該控件公開了一個我應該調用的Destroy方法,以允許控件正確地自行拆卸。當請求處理COM實例時,在後臺線程上執行控件的方法可能會非常好。 VFP是一個單線程單元模型,所以在調用Destroy時,它應該只添加到VFP執行堆棧中。COM在多線程環境中的處理

調用Destroy理想情況下是正確的,因爲它允許COM實例清理一些資源。我擔心的是,實例化VFP COM控件實際上啓動了一個VFP語言運行時實例,該控件託管在該實例中,並且該實例可能被鎖定(無響應)。這個COM組件在大型企業規模的20年曆史應用程序中公開了功能,並且我看到了.NET線程嘗試調用此控件上的方法的情況,只是在不拋出錯誤的情況下阻止(總是由傳統中的錯誤引起VFP代碼)。這並不經常發生,但它經常足以讓我建立一個實例管理器,該實例管理器在後臺線程中運行VFP COM實例上的方法,並定期檢查該線程是否被阻塞,如果是,則銷燬COM實例和線程,並重新啓動一個新的實例進行監控。

這是處理後臺方法可能執行的線程的正確方法嗎?

我應該試圖通過調用Destroy方法讓COM控件正確拆卸來獲得更好的效果嗎?

if (_vfpThread != null) 
{ 
    try 
    { 
    if (_vfpThread.IsAlive) 
     _vfpThread.Abort(); 
    } 
    catch (ThreadAbortException) 
    { } 
    finally 
    { 
    _vfpThread = null; 
    } 
} 

if (_vfpInstance != null) 
{ 
    Marshal.ReleaseComObject(_vfpInstance); 
    _vfpInstance = null; 
} 

回答

4

當一個方法調用一個基於VFP-COM對象未決(它總是處於STA公寓運行),調用從另一個線程相同的COM對象上的任何方法將阻塞,直到前調用返回(離開公寓)。這意味着,任何試圖同時調用Destroy()的線程都將受到第一個線程的支配。如果該線程不知道自動退出,理論上可能會使處理線程無限期地被阻塞。換句話說,沒有直接的方式來要求第一個線程通過調用另一個線程內的COM對象的另一個方法立即退出該方法。調用_vfpThread.Abort()應該可行,但這種方法的安全性很大程度上取決於VFP類的內部。 在許多情況下,由於它是遺留代碼,它不會像try/catch/finally部分那樣允許優雅退出,因此資源可能會被遺留下來而未被釋放。 - 壞!

另一種方法是在某個地方(註冊表,文件,任何地方)設置一個外部標誌,該標誌可以被第一個線程從正在執行的方法中讀取。這當然要求VFP類意識到必須從每個COM發佈的方法中讀取標誌,並且相應地並且迅速地採取行動。

此外,關於您的代碼片段。 在中止線程的代碼中捕獲ThreadAbortException只有在執行此代碼的線程正在中止時纔有意義。這會非常尷尬,因爲它可能只是從方法返回。 (或者,調用_vfpThread.Abort()的線程是否也可能會從另一個線程中被中止?) 在正常情況下,您需要包裝在ThreadAbortException捕獲器中的是執行調用的第一個線程的主代碼COM對象上的所有這些業務方法。 理想情況下,您可以像VFP方法一樣深入瞭解堆棧,在重新拋出異常之前代碼將能夠正常關閉所有資源/表等。 然後在傳遞給ThreadStart的主要方法中,除了它會從該方法和平地返回之外,您將擁有一個類似的捕獲器,從而終止線程或將其釋放到線程池。

+0

我不清楚上面的代碼是用於管理此VFP組件的類的Dispose方法。我當然可以嘗試優雅地關閉VFP線程,但這樣做可能需要一分鐘。 VFP線程使用AutoResetEvent通知主線程它已成功釋放其資源。問題是VFP線程被攻破時會發生什麼? WaitOne在60秒後超時,然後僅中止VFP線程。這對組件的正常關閉/重新啓動是正確的,但對於Dispose方法來說不是很好的做法。 Dispose應該做什麼? – RMart

+0

這是正確的做法。我將重寫代碼,以便嘗試關閉Dispose之外的VFP處理器。這是一個單獨的問題。也感謝您指出愚蠢的ThreadAbortException處理。 – RMart

0

是的,我確實瞭解你的代碼。謝謝。

如果vfp線程在60秒內沒有正常退出,則中止vfp線程也許是您可以做的唯一的事情。 關於Dispose應該做什麼 - 它應該盡最大努力釋放所有非託管資源,這些資源在VFP COM類中使用/打開時不幸被隱藏在此代碼中。所以,如果COM對象被佔用,主線程將無法強制它釋放這些資源。也許你可以嘗試的是將COM業務方法的整個主體封裝在VFP try-catch塊中,並在catch部分釋放資源/關閉表。 try-catch塊很有可能捕獲由主線程調用_vfpThread.Abort()所導致的ThreadAbortException。