C# 在返回值的函数上实现超时
我有一个函数,它调用串行端口上的读或写请求,然后返回读取的值。我正在使用Commstudio express(我正在从Commstudio实现一个类),但它的超时功能似乎根本不起作用,所以我正在尝试实现自己的超时。目前,我有一个定时器,可以根据请求设置为读取或写入端口,如果定时器关闭,回调将关闭连接,从而导致异常。我试图让计时器的回调抛出一个异常,但是异常需要通过调用原始读/写函数的线程向上传播,所以这样,它可以工作,但我觉得它很混乱,必须有更好的方法来完成我想要的操作。听起来像是在执行阻塞读/写。您要做的是非阻塞读/写 可能有一种方法可以告诉com端口您需要非阻塞 您确定超时不适用于commstudio吗?也许你必须做一些特殊的事情来初始化它们 在任何情况下,您都希望读取尽可能多的数据,如果没有可用的数据,则超时(取决于超时值)。您希望在没有可用数据和错误的情况下保持循环,然后在没有可用数据的情况下返回超时条件C# 在返回值的函数上实现超时,c#,.net,timeout,serial-port,C#,.net,Timeout,Serial Port,我有一个函数,它调用串行端口上的读或写请求,然后返回读取的值。我正在使用Commstudio express(我正在从Commstudio实现一个类),但它的超时功能似乎根本不起作用,所以我正在尝试实现自己的超时。目前,我有一个定时器,可以根据请求设置为读取或写入端口,如果定时器关闭,回调将关闭连接,从而导致异常。我试图让计时器的回调抛出一个异常,但是异常需要通过调用原始读/写函数的线程向上传播,所以这样,它可以工作,但我觉得它很混乱,必须有更好的方法来完成我想要的操作。听起来像是在执行阻塞读/
使read函数返回一个整数。负值=错误值,例如,-1=超时,读取的字节数为正数。。。至少我会这样做。这里有一个通用解决方案,允许您在超时时间内包装任何方法: 它使用有用的重载,以毫秒为单位接受超时,而不是手动使用计时器。唯一不同的做法是交换成功标志和结果值以匹配模式,如下所示:
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;
}
publicstatict执行(Func-Func,int超时)
{
T结果;
TryExecute(函数、超时、输出结果);
返回结果;
}
公共静态bool TryExecute(Func-Func、int超时、out T结果)
{
var t=默认值(t);
var线程=新线程(()=>t=func());
thread.Start();
var completed=thread.Join(超时);
如果(!completed)thread.Abort();
结果=t;
返回已完成;
}
以下是您将如何使用它:
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");
var func=new func(()=>
{
睡眠(200);
返回“成功”;
});
字符串结果;
Assert(!TryExecute(func,100,out result));
Assert(result==null);
Assert(TryExecute(func,300,out result));
Assert(result==“success”);
您还可以添加接受的重载,而不是要执行不返回值的方法的重载。对于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--;
}
如果有人想在VB.Net中做这件事,不要听那些说这件事做不到的人说! 您可能需要更改通用参数以适应您的用例
公共共享函数执行(Of I,R)(Func作为Func(Of I,R),输入作为I,超时作为整数)作为R
模糊结果为R
TryExecute(函数、输入、超时、结果)
返回结果
端函数
公共共享函数TryExecute(Of I,R)(Func作为Func(Of I,R),Input作为I,TimeOut作为整数,ByRef Result作为R)作为布尔值
变暗输出参数为R=无
将线程设置为新的System.Threading.Thread(Sub()InlineAssignHelper(OutParam,Func(Input)))
Thread.IsBackground=True
Thread.Start()
Dim已完成,布尔值=Thread.Join(超时)
如果未完成,则执行Thread.Abort()
结果=输出参数
返回已完成
端函数
InlineAssignHelper(Of T)中的私有共享函数(ByRef目标为T,ByVal值为T)为T
目标=价值
返回值
端函数
还有一个如何使用它的示例(我的示例是使用Regex.Match
,如果模式包含太多通配符,它有时会进入“永不”区域:
公共函数匹配(作为字符串输入)作为匹配
如果正则表达式为Nothing,则返回Nothing
Dim RegexMatch As System.Text.RegularExpressions.Match=无
Dim Func作为新Func(字符串的,System.Text.RegularExpressions.Match)(函数(x作为字符串)Regex.Match(x))
如果Runtime.TryExecute(字符串、System.Text.RegularExpressions.Match的值)(Func、Input、2000、RegexMatch),则
返回(新匹配(Me、Regex.Match(输入)、输入))
其他的
一无所获
如果结束
端函数
我很确定超时不起作用,DeviceError事件从未引发,甚至让它运行一个小时也不会发生任何事情。我的read函数是一个简单的重载,添加了一些自定义日志记录,但最后它是一个base.read()。这怎么办?更重要的是:在thread.Start()之前
,您应该设置thread.IsBackground=true
,否则线程在超时后继续运行,关闭应用程序后,它将在任务管理器中保持运行。@user227044线程启动后将中止两行代码。除非线程捕获ThreadAbortException并调用ResetAbort
,否则r某物抛出异常,我不知道线程如何保持运行。也就是说,在超时小于-1的情况下调用Join
,因此任何复制此代码的人都应该验证输入(如果这还不够设置IsBackground
),类似于