2009-10-02 26 views
0

我必須設置一個固定的超時爲特定的COM方法調用從我們有一個服務(這是用C#編寫的)。由於沒有使用System.Threading命名空間比Thread.Sleep其他任何東西,我有一齣戲,並想出了一個工作原型:如何有效地超時從C#代碼的COM方法調用

bool _comCallSuccessful = false; 
bool _timedOut = false; 

private void MakeACOMCallThatCouldTakeALongTime() 
{ 
    Thread.Sleep(2500); 
    _comCallSuccessful = true; 
} 

private void CheckForOneSecondTimeOut() 
{ 
    Thread.Sleep(1000); 
    _timedOut = true; 
} 

private void ThreadTester() 
{ 
    Thread t1 = new Thread(new ThreadStart(MakeACOMCallThatCouldTakeALongTime)); 
    Thread t2 = new Thread(new ThreadStart(CheckForOneSecondTimeOut)); 

    t1.Start(); 
    t2.Start(); 

    while (!_timedOut && !_comCallSuccessful) { } 

    if (_comCallSuccessful) 
    { 
     Console.WriteLine("Finished!"); 
    } 
    else 
    { 
     t1.Abort(); 
     Console.WriteLine("Timed out!"); 
    } 
    Console.ReadLine(); 
} 

實事求是地講,有沒有這種方法的問題?例如,如果我放棄調用COM方法的線程(也許是在清理使用的資源等方面),會不會有問題?

回答

2

Thread.Abort()is always a problem

你知道關於COM服務器的任何事嗎?它是否在進程中,進程外或遠程運行?如果COM服務器有問題,並且實際上需要終止它,請考慮在犧牲進程(或者至少一個單獨的AppDomain)中封裝調用,這可以安全地終止(也許你可以做一些作弊並終止冒犯的COM應用程序好)。如果你能幫助你的話,不要在你自己的過程中中止線程。

1

是的,很大的問題:它在很多情況下都不起作用。如果在調用Abort()時,您的COM線程在本地代碼中忙碌,則什麼都不會發生 - 它只是設置一個標誌,因此當線程返回到託管代碼時,它將彈出ThreadAbortException。沒有100%可靠的方法來中止對非託管代碼的調用。您可以嘗試殺死底層的操作系統線程,但是CLR不會對此做出反應,您可能會破壞該進程的穩定性。

+0

約Thread.Abort的不能夠放棄本地代碼調用好點的取消操作。 – jpoh 2009-10-05 02:20:13

1

我必須添加一個已經被其他評論者指出,像等待

while (!_timedOut && !_comCallSuccessful) { } 

是錯誤的,因爲它使你的CPU愚蠢花了個循環。

你最好使用System.Threading.EventWaitHandle:

EventwaitHandle _comCallSuccessful = new ManualResetEvent(false); 
EventwaitHandle _timedOut = new ManualResetEvent(false); 
private void MakeACOMCallThatCouldTakeALongTime() { 
    Thread.Sleep(2500); 
    _comCallSuccessful.Set(); 
} 

private void CheckForOneSecondTimeOut() { 
    Thread.Sleep(1000); 
    _timedOut.Set(); 
} 

private void ThreadTester() { 
    /* thread starting*/ 
    var handles = new WaitHandle[]{_comCallSuccessful, _timedOut}; 
    int indexFirstSet = Waithandle.WaitAny(handles); 
    if (indexFirstSet == 0) // _comCallSuccessful 
    { 
     Console.WriteLine("Finished!"); 
    } 
    else 
    { 
     t1.Abort(); 
     Console.WriteLine("Timed out!"); 
    } 
} 

如果有什麼可以做你的主線程,你可能會開始只有一個線程,並使用_comCallSuccessful.WaitOne(超時),返回如果在超時之前事件是Set(),則返回true。

不管怎樣,你最好有一個明確的方式爲您服務(例如COM對象的方法)

+0

感謝您的提示! – jpoh 2009-10-05 02:19:39

相關問題