C# 在返回值的函数上实现超时

C# 在返回值的函数上实现超时,c#,.net,timeout,serial-port,C#,.net,Timeout,Serial Port,我有一个函数,它调用串行端口上的读或写请求,然后返回读取的值。我正在使用Commstudio express(我正在从Commstudio实现一个类),但它的超时功能似乎根本不起作用,所以我正在尝试实现自己的超时。目前,我有一个定时器,可以根据请求设置为读取或写入端口,如果定时器关闭,回调将关闭连接,从而导致异常。我试图让计时器的回调抛出一个异常,但是异常需要通过调用原始读/写函数的线程向上传播,所以这样,它可以工作,但我觉得它很混乱,必须有更好的方法来完成我想要的操作。听起来像是在执行阻塞读/

我有一个函数,它调用串行端口上的读或写请求,然后返回读取的值。我正在使用Commstudio express(我正在从Commstudio实现一个类),但它的超时功能似乎根本不起作用,所以我正在尝试实现自己的超时。目前,我有一个定时器,可以根据请求设置为读取或写入端口,如果定时器关闭,回调将关闭连接,从而导致异常。我试图让计时器的回调抛出一个异常,但是异常需要通过调用原始读/写函数的线程向上传播,所以这样,它可以工作,但我觉得它很混乱,必须有更好的方法来完成我想要的操作。

听起来像是在执行阻塞读/写。您要做的是非阻塞读/写

可能有一种方法可以告诉com端口您需要非阻塞

您确定超时不适用于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
),类似于