1

I'm coding a function that receives a condition to be met and a time out and it finishes when the condition is met or it times out.

This is what I have so far :

public static bool CheckWithTimeout(bool toBeChecked, int msToWait)
{
    //var src = CancellationSource
    var task = Task.Run(()=> {
        while (!toBeChecked)
        {
            System.Threading.Thread.Sleep(25);
        }                    
    });
    if (task.Wait(TimeSpan.FromMilliseconds(msToWait)))
        return toBeChecked;
    else
        return false;
}

It works nice for simple bools but I would like to call it like:

CheckWithTimeout(myValue > 10, 500)

And it would return when myValue is bigger than ten, or 500 ms passed (and returns false in this case)

I checked and I think Func is what I need but.. I cannot find a proper example. Additionally, if there is an already existing method to achieve this I'd definitely prefer it.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
javirs
  • 1,049
  • 26
  • 52
  • Have you considered using the [timeout functionality](https://github.com/App-vNext/Polly/wiki/Timeout) of [Polly nuget package](http://www.thepollyproject.org/)? – Rui Jarimba Oct 19 '18 at 11:08
  • there is some polices about Nugets in my company so .. I'd rather code it – javirs Oct 19 '18 at 11:08
  • Possible duplicate of [Implement Timeout for function C#](https://stackoverflow.com/questions/31944324/implement-timeout-for-function-c-sharp) – Rui Jarimba Oct 19 '18 at 11:11
  • Check the answers in the above link, I think you'll find what you need. – Rui Jarimba Oct 19 '18 at 11:12
  • I strictly answered the question below, but functionally, I find it strange that you are not interested in the difference between "myValue <= 10" and the timeout. What do you conclude when the timeout occurs? – Remco te Wierik Oct 19 '18 at 12:52
  • I use it for unit testing. For instance I start an async server and I check if is open on the next seconds. I just assert.fail if values are bad or it times out – javirs Oct 19 '18 at 19:09

2 Answers2

2

If you use a simple bool parameter, it will be evaluated only once when the method is called. If you want to perform the evaluation multiple times, you need to use Func<bool>:

public static bool CheckWithTimeout(Func<bool> toBeChecked, int msToWait)
{
    //var src = CancellationSource
    var task = Task.Run(()=> {
        while (!toBeChecked())
        {
            System.Threading.Thread.Sleep(25);
        }                    
    });
    if (task.Wait(TimeSpan.FromMilliseconds(msToWait)))
        return toBeChecked();
    else
        return false;
}

Now you can use a lambda to call the method:

CheckWithTimeout(() => myValue > 10, 500)

Or just create a method which returns a bool and pass its name in.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
2

It's better to use separate tasks for the result and the waiting.

    private async Task<bool> CheckWithTimeout(Func<bool> toBeChecked, int msToWait)
    {
        var waitTask = Task.Delay(msToWait);
        var checkTask = Task.Run(toBeChecked);
        await Task.WhenAny(waitTask, checkTask);
        return checkTask.IsCompleted && await checkTask;
    }


    private async Task<bool> CheckWithTimeout<T>(Predicate<T> toBeChecked, T predicateParameter, int msToWait)
    {
        var waitTask = Task.Delay(msToWait);            
        var checkTask = Task.Run(() => toBeChecked(predicateParameter));
        await Task.WhenAny(waitTask, checkTask);
        return checkTask.IsCompleted && await checkTask;
    }

That way you do not nescessary have to wait for the timeout. (And Taks.Delay is better than Task.Wait because it doesn't block)

Edit: Example with function or predicate

Remco te Wierik
  • 1,436
  • 2
  • 10
  • 10
  • how do I call the predicate method ? – javirs Oct 19 '18 at 12:08
  • A Predicate tests input for a set of criteria. So if your predicate is var isOddYear = new Predicate(date => date.Year % 2 == 1); and you want to test the current year, your call would be: var result = CheckWithTimeout(isOddYear, DateTime.Today, 500); – Remco te Wierik Oct 19 '18 at 12:32
  • sounds way more verbose than the Func version .. why is it preferred ? – javirs Oct 19 '18 at 12:36
  • The title says you want to check predicates (test a value for a set of criteria). So then you should provide the predicate and the value to test. And for the sake of this question, the timeout delay. If you just want to execute a function that returns a bool, you don't need the predicate overload. – Remco te Wierik Oct 19 '18 at 12:47
  • how do I wait the method and get the bool. I cannot use the await because my UT cannot be async – javirs Oct 22 '18 at 10:29
  • Ok, found it, my test method has to be public async Task name to be able to run await on it. I was trying with public async void Name ... fixed ! – javirs Oct 22 '18 at 10:46