Search code examples
c#.nettimeoutserial-port

Implementing a timeout on a function returning a value


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.


Solution

  • 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.