在返回值的函数上实现超时
Posted
技术标签:
【中文标题】在返回值的函数上实现超时【英文标题】:Implementing a timeout on a function returning a value 【发布时间】:2010-11-25 03:25:44 【问题描述】:我有一个函数调用串行端口上的读取或写入请求,然后返回读取的值。我正在使用 Commstudio express(我正在从 Commstudio 实现一个类),但它的超时功能似乎根本不起作用,所以我正在尝试实现我自己的超时。目前我有一个计时器,它根据请求设置读取或写入端口,如果计时器关闭,回调将关闭连接导致异常。我试图让定时器的回调抛出一个异常,但是异常需要通过调用原始读/写函数的线程向上传播,所以这样就可以了,但是我觉得它很乱必须是做我想做的更好的方法。
【问题讨论】:
类似***.com/questions/299198/… 【参考方案1】:这是一个通用解决方案,允许您在超时中包装任何方法:
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 的重载。
【讨论】:
这个***.com/a/990566/206730 怎么样?更多内容***.com/questions/299198/… 重要提示:在thread.Start()
之前,你应该设置thread.IsBackground = true
,否则线程超时后继续运行,关闭应用程序后,它会在任务管理器中继续运行。
@user2270404 线程在启动后中止了两行代码。除非线程捕获到 ThreadAbortException 并调用ResetAbort
,或者引发异常,否则我看不到线程如何继续运行。也就是说,以小于 -1 的超时时间调用 Join
将 throw an exception,因此任何复制此代码的人都应该验证输入(如果感觉还不够设置 IsBackground
) .【参考方案2】:
听起来您正在执行阻塞读/写。您要做的是非阻塞读/写。
可能有一种方法可以告诉 com 端口您想要非阻塞。
您确定超时不适用于 commstudio 吗?也许你必须做一些特别的事情来初始化它们。
在任何情况下,您都希望读取尽可能多的数据,如果没有可用则超时(取决于超时的值)。您会希望在没有可用数据且没有错误的情况下继续循环,然后在没有可用数据时返回超时条件。
让你的读取函数返回一个整数。负值 = 错误值-1 = 超时,读取的字节数为正数……至少我会这样做。
【讨论】:
我很确定超时不起作用,DeviceError 事件永远不会引发,即使让它运行一个小时也没有任何反应。我的读取函数是一个简单的重载,它添加了一些自定义日志记录,但最终,它是一个 base.Read()。【参考方案3】:对于 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--;
【讨论】:
【参考方案4】:如果有人想在 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
,如果模式包含太多通配符,它有时会变成永远不会落地:
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
【讨论】:
以上是关于在返回值的函数上实现超时的主要内容,如果未能解决你的问题,请参考以下文章