2009-09-03 40 views
11

我有一個函數調用串口讀取或寫入請求,然後返回讀取的值。我正在使用Commstudio express(我正在從Commstudio實施一個課程),但它的超時功能似乎根本不起作用,所以我試圖實現我自己的超時。目前我有一個計時器,根據請求設置爲讀或寫端口,如果計時器關閉,回調關閉導致異常的連接。我試圖讓計時器的回調拋出一個異常,但是異常需要通過調用原始讀/寫函數的線程傳播,所以通過這種方式,它可以工作,但我覺得它很混亂,而且在那裏必須是更好的方式來做我想做的事。在返回值的函數上實現超時

+0

類似的HTTP://堆棧溢出。com/questions/299198/implement -c-sharp-generic-timeout – Kiquenet 2013-04-12 09:08:55

回答

34

這裏是一個通用的解決方案,允許你包裝任何方法在一個超時:

http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time/

它使用有用Thread.Join過載,其接受以毫秒爲單位而不是使用定時器手動。我會做出不同的唯一事情是交換的成功標誌和結果值的TryParse模式相匹配,具體如下:

public static T Execute<T>(Func<T> func, int timeout) 
{ 
    T result; 
    TryExecute(func, timeout, out result); 
    return result; 
} 

public static bool TryExecute<T>(Func<T> func, int timeout, out T result) 
{ 
    var t = default(T); 
    var thread = new Thread(() => t = func()); 
    thread.Start(); 
    var completed = thread.Join(timeout); 
    if (!completed) thread.Abort(); 
    result = t; 
    return completed; 
} 

這是你將如何使用它:

var func = new Func<string>(() => 
    { 
     Thread.Sleep(200); 
     return "success"; 
    }); 
string result; 
Debug.Assert(!TryExecute(func, 100, out result)); 
Debug.Assert(result == null); 
Debug.Assert(TryExecute(func, 300, out result)); 
Debug.Assert(result == "success"); 

你也可以如果您要執行不返回值的方法,請添加接受Action而不是Func的超載。

+0

這是什麼http://stackoverflow.com/a/990566/206730?更多在http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout – Kiquenet 2013-04-12 09:08:39

+1

**重要提示:**在thread.Start()之前,您應該設置'thread.IsBackground = true'線程在超時後繼續運行,關閉應用程序後,它將保持在任務管理器中運行。 – 2013-09-03 11:54:05

+0

@ user2270404線程在啓動後會中止兩行代碼。除非線程捕獲ThreadAbortException並調用'ResetAbort',否則會引發異常,我看不到線程可以繼續運行。 這就是說,調用具有小於-1 **的超時的'Join'將會[引發異常](http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx),所以任何人複製這段代碼應該驗證輸入(如果這樣做不足以設置'IsBackground')。 – 2013-12-11 21:28:55

2

聽起來像你正在做阻塞讀/寫。你想要做的是一個非阻塞的讀/寫。

可能有辦法告訴com端口你想要非阻塞。

您確定超時時間不適用於commstudio嗎?也許你必須做一些特別的事情來初始化它們。

在任何情況下,您都希望儘可能多地讀取數據,如果沒有可用的超時時間(取決於超時的值)。如果沒有可用的數據並且沒有錯誤,您將希望保持循環,然後返回超時條件。

使你的讀取函數返回一個整數。負值=錯誤值例如-1 =超時,讀取的正數字節......至少這就是我要做的方式。

+0

我很確定超時不工作,DeviceError事件永遠不會發生,即使將它運行一個小時也不會發生任何事情。我的閱讀函數是一個簡單的重載,它增加了一些自定義日誌記錄,但最終它是一個base.Read()。 – MGSoto 2009-09-03 07:01:09

0

對於comport,您可以測試是否有任何可用的內容,然後執行讀取操作,而不是在不知道還有什麼內容的情況下執行阻止讀取操作。喜歡的東西:

Int32 timeout=1000; 
String result = String.Empty'; 
while (timeout!=0) { 
    if (Serial.BytesToRead>0) { 
    while (Serial.BytesToRead>0) { 
     result+=Serial.ReadChar(); 
    } 
    break; 
    } 
    Thread.Sleep(1); 
    timeout--; 
} 
0

如果有人想這樣做在VB.Net,不要聽那些誰說不能這樣做! 您可能需要更改通用參數以適合您的用例。

Public Shared Function Execute(Of I, R)(Func As Func(Of I, R), Input As I, TimeOut As Integer) As R 
    Dim Result As R 
    TryExecute(Func, Input, TimeOut, Result) 
    Return Result 
    End Function 

    Public Shared Function TryExecute(Of I, R)(Func As Func(Of I, R), Input As I, TimeOut As Integer, ByRef Result As R) As Boolean 
    Dim OutParam As R = Nothing 
    Dim Thread As New System.Threading.Thread(Sub() InlineAssignHelper(OutParam, Func(Input))) 
    Thread.IsBackground = True 
    Thread.Start() 
    Dim Completed As Boolean = Thread.Join(TimeOut) 
    If Not Completed Then Thread.Abort() 
    Result = OutParam 
    Return Completed 
    End Function 

    Private Shared Function InlineAssignHelper(Of T)(ByRef Target As T, ByVal Value As T) As T 
    Target = Value 
    Return Value 
    End Function 

以及如何使用它的一個例子(我的是與Regex.Match,有時熄滅到永遠,如果模式包含了太多的通配符NEVER LAND:

Public Function Match(Input As String) As Match 
    If Regex Is Nothing Then Return Nothing 
    Dim RegexMatch As System.Text.RegularExpressions.Match = Nothing 
    Dim Func As New Func(Of String, System.Text.RegularExpressions.Match)(Function(x As String) Regex.Match(x)) 
    If Runtime.TryExecute(Of String, System.Text.RegularExpressions.Match)(Func, Input, 2000, RegexMatch) Then 
     Return (New Match(Me, Regex.Match(Input), Input)) 
    Else 
     Return Nothing 
    End If 
    End Function