对返回值的函数实现超时

发布于 2024-08-04 03:49:49 字数 251 浏览 4 评论 0原文

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

I have a function that calls out a read or write request on a serial port and then returns the value that was read. I am using Commstudio express (I'm implementing a class from Commstudio) , but it's timeout features don't appear to work at all, so I'm trying to implement my own timeout. Currently I have a timer that is set upon request to read or write to the port, and if the timer goes off, the callback closes the connection causing an exception. I tried to have the callback of the timer throw an exception, but the exception needs to be propagated up through the thread that was calling the original read/write function, so in this way, it works, but I feel like it's messy and there must be a better way to do what I want.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

心欲静而疯不止 2024-08-11 03:49:49

这是一个通用解决方案,允许您在超时中包装任何方法:

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");

您还可以添加接受 操作 而不是 Func 如果你想执行一个不返回值的方法。

Here is a generic solution that allows you to wrap any method in a timeout:

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

It uses the useful Thread.Join overload that accepts a timeout in milliseconds rather than manually using timers. The only thing I would do differently is swap the success flag and result value to match the TryParse pattern, as follows:

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;
}

And this is how you would use it:

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");

You could also add overloads that accept Action instead of Func if you want to execute a method that doesn't return a value.

归途 2024-08-11 03:49:49

听起来你正在执行阻塞读/写操作。您想要做的是非阻塞读/写。

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

您确定超时不适用于 commstudio 吗?也许你必须做一些特殊的事情来初始化它们。

在任何情况下,您都希望读取尽可能多的数据,如果没有可用的数据,则超时(取决于超时的值是多少)。您需要在没有可用数据且没有错误的情况下继续循环,然后在没有任何可用数据时返回超时条件。

让您的读取函数返回一个整数。负值=错误值,例如-1=超时,读取的正字节数...至少我就是这样做的。

Sounds like you're doing a blocking read/write. What you want to do is a non-blocking read/write.

There is probably a way to tell the com port that you're wanting non- blocking.

Are you sure the timeouts are not working with commstudio? maybe you have to do something special to initialise them.

In any case, you want to read as much data as possible and if none is available time out (depending on what the value of the time out is). You'll want to keep looping while no data available and no error and then return a time out condition if there wasn't anything available.

Make your read function return an integer. negative values = error value e.g. -1 = timeout, positive number of bytes read... at least thats the way I'd do it.

瑶笙 2024-08-11 03:49:49

您可以创建一个扩展方法,该方法将 TaskT 类型的 defaultValue 作为输入。这是我的实现。

 public static class Helpers
    {
        public static Task<T> SetTimeout<T>(this Task<T> task, T defaultValue, int timeoutInMilliseconds = 1000)
        {
            var timeout = Task.Delay(timeoutInMilliseconds);
            Task.WaitAny(task, timeout);

            if (!task.IsCompleted)
                return Task.FromResult(defaultValue);

            return task;
        }
    }

这是一个用法示例:

var cars = await _myService.GetCars().SetTimeout(new List<string>() { "Toyota", "Nissan" });

You can create an extension method that takes the Task<T> and a defaultValue of type T as input. Here is my implementation.

 public static class Helpers
    {
        public static Task<T> SetTimeout<T>(this Task<T> task, T defaultValue, int timeoutInMilliseconds = 1000)
        {
            var timeout = Task.Delay(timeoutInMilliseconds);
            Task.WaitAny(task, timeout);

            if (!task.IsCompleted)
                return Task.FromResult(defaultValue);

            return task;
        }
    }

Here is a usage example:

var cars = await _myService.GetCars().SetTimeout(new List<string>() { "Toyota", "Nissan" });
怕倦 2024-08-11 03:49:49

对于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--;
}

For the comport you could just test if there is anything available and then do a read instead of doing a blocking read without knowing there is something yet. Something like:

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--;
}
樱桃奶球 2024-08-11 03:49:49

如果有人想在 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 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

In case someone wants to do this in VB.Net, don't listen to those who say it can't be done!
You may need to alter your generic parameters to suit your use case.

  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

And an example of how to use it (mine was with Regex.Match, which sometimes goes off into never never land if the patterns contains too many wild cards:

  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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文