.net construct for while loop with timeout
Solution 1
You could wrap your algorithm in a method:
public bool RetryUntilSuccessOrTimeout(Func<bool> task, TimeSpan timeSpan)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeSpan.TotalMilliseconds))
{
Thread.Sleep(1000);
elapsed += 1000;
success = task();
}
return success;
}
and then:
if (RetryUntilSuccessOrTimeout(() => SomeTask(arg1, arg2), TimeSpan.FromSeconds(10)))
{
// the task succeeded
}
Solution 2
You could use SpinWait.SpinUntil
See https://msdn.microsoft.com/en-us/library/dd449238(v=vs.110).aspx
bool spinUntil = System.Threading.SpinWait.SpinUntil(() => job.IsDisposed, TimeSpan.FromSeconds(5));
Solution 3
You really should not have to use Sleep()
to wait for tasks to complete. You waste an average of 500ms after the task has completed by doing this.
You ought to be able to do this deterministically using Task Parallel Library, see here for example.
This example shows how to use the Wait method, or its equivalent in the Task class, to wait on a single task. It also shows how to use the static WaitAll and WaitAny methods to wait on multiple tasks.
Solution 4
I don't know that there's any existing thing, but I would think you could create a method to that would accept the timeout and the success-determination function. Something like this:
public static bool KeepTrying(int timeout, Func<bool> operation)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeout))
{
Thread.Sleep(1000);
elapsed += 1000;
success = operation();
}
return success;
}
or maybe your Function could be more "robust" and you could couple it with flexible arguments:
public bool KeepTrying(int timeout, Func<object[], bool> operation, params object[] arguments)
{
bool success = false;
int elapsed = 0;
while ((!success) && (elapsed < timeout))
{
Thread.Sleep(1000);
elapsed += 1000;
success = operation(arguments);
}
return success;
}
Solution 5
The first solution is to use SpinWait
SpinWait.SpinUntil(() => LoopProcedure(), 1000);
The other solution is to use Task.Wait()
var task = Task.Run(() => LoopProcedure());
task.Wait(1000);
Wrap your loop into a procedure that return bool value
private bool LoopProcedure()
{
bool success = false
while( ( !success )
{
// do some stuff ...
}
return success;
}
Related videos on Youtube
Suraj
Hi! I'm Suraj and here is a little about me, on my blog That! But How?
Updated on July 09, 2022Comments
-
Suraj almost 2 years
I commonly employ a while loop that continues to try some operation until either the operation succeeds or a timeout has elapsed:
bool success = false int elapsed = 0 while( ( !success ) && ( elapsed < 10000 ) ) { Thread.sleep( 1000 ); elapsed += 1000; success = ... some operation ... }
I know there a couple of way to implement this, but the basic point is that I repeatedly try some operation with a sleep until success or I've slept too long in aggregate.
Is there a built-in .net class/method/etc to save me from re-writing this pattern all over the place? Perhaps input is an Func(of bool) and the timeout?
Edit
Thanks to all who contributed. I opted for the sleep() approach because it was the least complicated and I'm totally anti-complexity =) Here's my (still needs to be tested) implimentation:public static bool RetryUntilSuccessOrTimeout( Func<bool> task , TimeSpan timeout , TimeSpan pause ) { if ( pause.TotalMilliseconds < 0 ) { throw new ArgumentException( "pause must be >= 0 milliseconds" ); } var stopwatch = Stopwatch.StartNew(); do { if ( task() ) { return true; } Thread.Sleep( ( int )pause.TotalMilliseconds ); } while ( stopwatch.Elapsed < timeout ); return false; }
-
BoltClock almost 13 yearsYou tagged with two .NET Framework versions, so which are you looking to have a solution compatible with?
-
Cos Callis almost 13 yearsI don't know of a utility that will do this for your, but you might try building an extension method (maybe of 'object') ... but that may be all a little too disconnected and abstract...
-
Suraj almost 13 years@BoltClock - sorry, I'm on 4.0
-
Suraj almost 13 yearsAll - wow! I didn't expect so many answers. bear with me while I digest it all. =)
-
-
Hasan Fahim almost 13 yearsThe purpose of Thread.Join is to block the current thread till the activity which is being performed on it ends.
-
Admin almost 13 years@Hasan: What do you think his While loop is doing? Also, Thread.Join continues to perform standard COM and SendMessage pumping so as to not block the UI thread.
-
Hasan Fahim almost 13 yearsIf you look at the article you provided. It is mentioned in it that "Use this method to ensure a thread has terminated. The caller will block indefinitely if the thread does not terminate. If the thread has already terminated when Join is called, the method returns immediately"
-
Admin almost 13 years@Hasan: Exactly, then there is no time to wait. What is the problem?
-
Hasan Fahim almost 13 yearsIn other words, when you start a thread, the calling thread is blocked until the thread terminates.
-
Admin almost 13 years@Hasan: Except for COM and Windows Message Pumps. - This replicates what he is doing already with the While loop.
-
Suraj almost 13 years@0A0D (cool name) - Thread.Join(TimeSpan) is not the solution in itself right? I would have to launch another thread with the while loop...and although the timeout would guarantee that I move on, what happens if the launched thread is now in an infinite loop? I'm having trouble seeing the full solution here.
-
Suraj almost 13 yearsthanks! looks like the same solution as scottm (or vice-versa =)
-
Suraj almost 13 yearshmm...this doesn't seem as elegant as scottm's solution
-
Darin Dimitrov almost 13 years@SFun28, I have posted my solution 19 minutes ago, while @scottm posted his 18 minutes ago. Up to you to decide whose solution came first.
-
Admin almost 13 years@SFun28: your provided while loop has an elapsed time. It is assumed that the work will take x amount of time. If you need more time, then you should let the user know. Your worker thread can always stop after the elapsed time too.
-
myermian almost 13 yearsI never said it was. I'm just throwing an option out there.
-
Hasan Fahim almost 13 years@0A0D. Where is there Thread.Start, that you are calling Thread.Join? Also join is not a static function, so you need to call it on some thread object e.g newThread.Join. Besides you haven't specified where the user should use Join? You should have posted a snippet to make your answer more understandable. Anyways...
-
Admin almost 13 years@Hasan: Sour grapes? He wanted to know if there was a built-in way to do it. I provided it. You are free to provide your own answer.
-
Suraj almost 13 yearsgood idea about robustness! After all, I might want to specify arguments to my function. Wondering if there's a way that I can pre-construct the Func with arguments and take advantage of the closure?
-
scottm almost 13 years@SFun28 you'd have to overload the function and pass in however many arguments you want to allow. For example, look at these overloads: msdn.microsoft.com/en-us/library/dd402862.aspx
-
Suraj almost 13 yearsDo you mean the waste is attributed to the Sleep() method itself or because I might sleeping when the operation would have completed? What if the operation requires a network call (i.e. something you do not necessarily want to keep firing out without some kind of pause in-between calls? Also, there's the issue of waiting for something that doesn't complete (even with a timeout, I don't want to keep a thread in an infinite loop)
-
Hasan Fahim almost 13 years:-) It's not about sour grapes. I guess we all are here for the purpose of learning and it's not bad in admitting that we don't know something. So anyways we should have a look at the right solutions that others have provided and learn what we don't know.
-
Suraj almost 13 years@0A0D - I too am having difficulty understanding your solution. I think I need to be more clear about my goals: 1. periodically try some operation and stop if it succeeds. 2. ensure that I'm not caught in an infite loop by having a timeout. Perhaps some pseudocode would help me.
-
Steve Townsend almost 13 yearsSleep() will wait for 1 second even if the operation completes 1ms after the Sleep() was called. That's what I meant. For waiting for possibly infinite operations, there are
Wait(timeout)
options as shown in that example and also for regular Synchronization using Events, Semaphores etc for cross-thread signalling. If the operation requires a delay between invocations, have it fire from a callback onSystem.Threading.Timers.Timer
rather than hanging up your thread inSleep
. -
Suraj almost 13 yearsGreat idea about the Timer. So I get the idea of launching a task and waiting for it to complete given a timeout, but after that timeout I have to signal for the Timer to stop. And of course if the operation succeeds before the timeout I want to stop immediately. I'm not sure how I put all of this together...seems like a complicated mix of Timer class and TPL
-
Steve Townsend almost 13 yearsGood threaded code is indeed hard to write. TPL certainly makes it easier though. Code defensively (try..catch is your friend) and test extensively. Prototyping a new improved design in C# is a lot easier than native code would be.
-
Suraj almost 13 yearsAlso, I think everyone is assuming this call is happening on my main thread, but in fact this code is executing within a thread generated from the main thread, so not sure if that changes the answer?
-
Admin almost 13 years@SFun28: Does not change my answer. You have the possibility of two threads here.
-
Suraj almost 13 yearsI like that your function returns the true/false result and also good function name! Thanks, Darin!
-
Jerry Nixon almost 7 yearsI don't understand why this was not marked as the answer. It is clearly the answer - better than any of the other suggestions 100%.
-
user14761301 over 6 yearsjust a note, even though loop times out, action continues to execute in the above code