2012-02-21 30 views
0

長話短說:在C#應用程序與COM進程內服務器(DLL)的作品,我會遇到‘0x80010100:系統調用失敗’異常,並在調試模式下也ContextSwitchDeadlock例外。0x80010100:系統調用失敗」的例外,ContextSwitchDeadlock

現在,在細節更:

1)C#應用程序初始化STA,創建一個COM對象(登記爲「單元」);然後在訂閱了它的連接點,並開始與該對象工作

2)在某些階段的COM對象產生了很多的事件,作爲參數傳遞COM objec非常大集合ts,它們在同一個房間中創建。

3)C#一側的事件處理程序處理上述收集,偶爾調用對象的一些方法。在某些階段,由於上述例外情況,後者的通話開始失敗。

在COM端公寓使用一個隱藏的窗口,其Winproc傳看起來是這樣的:

typedef std::function<void(void)> Functor; 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
    switch(msg) 
    { 
    case AM_FUNCTOR: 
    { 
     Functor *f = reinterpret_cast<Functor *>(lParam); 
     (*f)(); 
     delete f; 
    } 
    break; 
    case WM_CLOSE: 
     DestroyWindow(hwnd); 
    break; 
    default: 
     return DefWindowProc(hwnd, msg, wParam, lParam); 
    } 
    return 0; 
} 

事件被髮布到從COM服務器的其他部分窗口:

void post(const Functor &func) 
{ 
    Functor *f = new Functor(func); 
    PostMessage(hWind_, AM_FUNCTOR, 0, reinterpret_cast<LPARAM>(f)); 
} 

的事件是與實際參數綁定的標準ATL CP實現,並且它們歸結爲如下所示:

pConnection->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, &varResult, NULL, NULL); 

在C#中的處理程序是這樣的:

private void onEvent(IMyCollection objs) 
{ 
    int len = objs.Count; // usually 10000 - 25000 
    foreach (IMyObj obj in objs) 
    { 
    // some of the following calls fail with 0x80010100 
    int id = obj.id; 
    string name = obj.name; 
    // etc... 
    } 
} 

==================

因此,可以將上述問題發生,只是因爲消息公寓的排隊裝滿了它試圖提供的事件?或者消息循環應該被完全阻塞以導致這樣的行爲?

讓我們假設該消息隊列有一個評價爲「的onEvent」呼2個連續的事件。第一個輸入C#託管代碼,該代碼嘗試重新輸入非託管代碼,同一個公寓。通常情況下,這是允許的,我們做了很多。何時,在什麼情況下它可能會失敗?

謝謝。

+1

這通常是COM服務器崩潰造成的,通常是由AccessViolation引起的。您需要調試服務器。 – 2012-02-21 13:40:06

+0

@Hans Passant正如我所提到的,我的服務器是dll,我通過啓用「調試非託管代碼」來與C#應用程序一起調試它。不,沒有任何內部崩潰的dll。 – 2012-02-21 22:08:00

回答

2

這應該提供與多個公寓甚至工作:

  • 線程只有一個響應外部事件,比如網絡流量,定時器,發佈的消息等
  • 其他線程僅服務COM請求(即使他們在處理過程中回到主線程)。

  • 沒有線程隊列不斷變滿,防止COM從與線程通信。

首先: 看起來有些對象不在同一間公寓內的其他對象。你確定所有對象都在STA中創建嗎?

你所描述的是一個經典的死鎖 - 兩個獨立的線程,每個線程都在等待另一個線程。這是我期望在不同線程上使用C#和COM端進行設計時發生的情況。

你應該可以,如果全部對象是在同一個線程,以及隱藏窗口正在該線程,所以我認爲你需要檢查。 (顯然這包括由COM端創建並傳遞到C#端的任何其他對象)。

您可以嘗試通過在調試器中按下「pause」來調試它,並檢查每個線程中的代碼是什麼(if你看到RPCRT * .DLL這意味着你正在尋找一個代理)。或者,您可以在C#和COM端以及您的WndProc中的各個關鍵點DebugPrint當前線程ID - 它們應該都是相同的。

其次:它應該與多線程工作規定,只有一個線程產生的工作項目,以及其他什麼也不做,但要呼籲作出響應主機的COM對象(即不產生來自計時器,網絡電話流量,發佈的消息等),在這種情況下可能是線程隊列已滿並且COM無法回覆呼叫。

而不是使用線程隊列,您應該使用臨界區保護的雙端隊列。

您可能會維護一個項目開/關的計數器,以查看這是否是問題。

+0

感謝您的詳細解答。顯然,無論是死鎖還是消息隊列溢出(> 10K消息)似乎都是如此,但我會更徹底地再次檢查這些問題。 – 2012-02-21 22:05:22

+0

你說得對,它是一個消息隊列溢出。飛機飛過後,公寓信息肯定無法處理。 – 2012-02-28 17:32:47

相關問題