I want to run a function on an interval, inside of a Task. Something like,
Task t = Task.Factory.StartNew(() => {
while (notCanceled()) {
doSomething();
Thread.Sleep(interval);
}
});
Is it a bad idea to use Thread.Sleep() here? The task is long running, and the sleep time may also be very long (minutes, maybe even hours).
One alternative is to use either System.Timers.Timer or System.Threading.Timer. However both of these would cause an additional thread to spawn (the Elapsed events occur on a new threadpool thread). So for every repeating task, there would be 2 threads instead of 1. The Task is already asynchronous so I'd prefer not to complicate things in this way.
Yet another way that behaves similarly is to use ManualResetEvent,
ManualResetEvent m = new ManualResetEvent(false);
void sleep(int milliseconds)
{
m.WaitOne(milliseconds);
}
Since m.Set() would never be called, this would always wait for the right amount of time, and also be single threaded. Does this have any significant advantage over Thread.Sleep()?
Wondering what the best practice would be here.
Thoughts?
If you're using C# 5.0 you can use:
while(notCanceled())
{
doSomething();
await Task.Delay(interval);
}
If you're using an earlier version your best bet is probably to use a Timer.
Both of the code samples you showed, involving either Thread.Sleep or a ManualResetEvent are blocking the current thread for that duration, which means your code is tying up a thread which can't do anything else until your task is canceled. You don't want to do that. If you use a timer, or the await code mentioned above, you will end up not blocking any thread at all while waiting, and then use up a thread pool's time only when you have productive work to be doing.
Yes, it is a very bad idea to use sleep in a loop like that.
You have a faulty understanding of timers. Creating a timer does not create a new thread. The timer sets an operating system trigger that, when the time elapses, spawns a threadpool thread. So if you write:
System.Threading.Timer myTimer =
new Timer(DoStuff, null,
TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
The only time there will be another thread is when the handler method (DoStuff) is executing.
There'd be no reason to have the task if everything it does is handled by your DoStuff method. If you want to cancel it, just dispose the timer.
I strongly recommend, by the way, that you not use System.Timers.Timer. In short, it squashes exceptions, which hides bugs. See Swallowing exceptions is hiding bugs.
Related
This question already has answers here:
When to use Task.Delay, when to use Thread.Sleep?
(10 answers)
Closed 3 years ago.
I was wondering if there is any problem if i want to pause a thread for a defined period of time at every iteration ( i am running a continous loop).
My first choice was using Task.Delay but i do not know if there could be any issues.Should i just go for Thread.Sleep or EventWaitHandle ?
class UpdateThread {
private Thread thread;
Fabric.Client client;
public UpdateThread(Fabric.Client client) {
}
public void Run() {
thread = new Thread(new ThreadStart(async()=>await UpdateAsync()));
}
public async Task UpdateAsync() {
while (true) {
await Task.Delay(Constants.REFRESH_INTERVAL);
}
}
}
What are the downsides to the above mentioned methods ?
P.S: This thread is running alongside a Windows Forms application (thread)
There is a potential problem with the ThreadStart delegate that you pass to the Thread's constructor, which is defined as public delegate void ThreadStart(). The fact that you provide an async void lambda for it makes it a fire-and-forget call. I.e., it's asynchronous but it doesn't return a Task to observe for result or exceptions.
Your new thread will most likely end as soon as the execution flow inside it hits the first await something, be it await Task.Delay or anything else. So, technically, you're not pausing a thread here. The logical execution after that await will continue on a random thread pool thread, which will most likely be different from the thread you initially created.
You'd be better off just using Task.Run instead of new Thread. The former has an override for async Task lambdas, which you should normally be using instead of async void anyway. Thus, you could pass your UpdateAsync directly to Task.Run and have the proper exception propagation logic for async methods.
If for some reason you still want to stick with new Thread and pass an async void lambda to it, make sure to observe all exception thrown by UpdateAsync. Otherwise, they will be thrown "out-of-band" on a random pool thread, see the above link for more details. Also note, creating a new thread (and then almost instantly ending it) is a rather expensive runtime operation. OTOH, when using Task.Run, you normally just borrow/return an existing thread from/to thread pool, which is much faster.
That said, in this particular case you may as well just be using Thread.Sleep instead of async methods and Task.Delay, to avoid having to deal with asynchrony and thread switching at all. It's a client-side WinForms application where you normally don't care (to a reasonably extent) about scaling, i.e., the number of busy or blocked threads.
In this case you should use Task.Delay, because Thread.Sleep would send a Thread from the .NET ThreadPool to sleep and that is most likely not what you want. You are also mixing lower-level Thread with higher-level Task. You don't need to start a new thread. It is enough to just call UpdateAsync() without calling Wait() or similar.
Use Thread.Sleep when you want to block the current thread.
Use Task.Delay when you want a logical delay without blocking the current thread.
Source
I prefer handling such cases with a Thread.Sleep cause it's lower level and more effectively in my head, but it's just a personal thing.
I have a button which has an async handler which calls awaits on an async method. Here's how it looks like:
private async void Button1_OnClick(object sender, RoutedEventArgs e)
{
await IpChangedReactor.UpdateIps();
}
Here's how IpChangedReactor.UpdateIps() looks:
public async Task UpdateIps()
{
await UpdateCurrentIp();
await UpdateUserIps();
}
It's async all the way down.
Now I have a DispatcherTimer which repeatedly calls await IpChangedReactor.UpdateIps in its tick event.
Let's say I clicked the button. Now the event handler awaits on UpdateIps and returns to caller, this means that WPF will continue doing other things. In the meantime, if the timer fired, it would again call UpdateIps and now both methods will run simultaneously. So the way I see it is that it's similar to using 2 threads. Can race conditions happen? (A part of me says no, because it's all running in the same thread. But it's confusing)
I know that async methods doesn't necessarily run on separate threads. However, on this case, it's pretty confusing.
If I used synchronous methods here, it would have worked as expected. The timer tick event will run only after the first call completed.
Can someone enlighten me?
Since both calls run on the UI thread the code is "thread safe" in the traditional sense of - there wouldn't be any exceptions or corrupted data.
However, can there be logical race conditions? Sure. You could easily have this flow (or any other):
UpdateCurrentIp() - button
UpdateCurrentIp() - Timer
UpdateUserIps() - Timer
UpdateUserIps() - button
By the method names it seems not to really be an issue but that depends on the actual implementation of these methods.
Generally you can avoid these problems by synchronizing calls using a SemaphoreSlim, or an AsyncLock (How to protect resources that may be used in a multi-threaded or async environment?):
using (await _asyncLock.LockAsync())
{
await IpChangedReactor.UpdateIps();
}
In this case though, it seems that simply avoiding starting a new update when one is currently running is good enough:
if (_isUpdating) return;
_isUpdating = true;
try
{
await IpChangedReactor.UpdateIps();
}
finally
{
_isUpdating = false;
}
I can think of a number of ways to handle this issue
1 Do not handle it
Like i3arnon says it might not be a problem to have multiple calls to the methods running at the same time. It all depends on the implementation of the update methods. Just like you write, it's very much the same problem that you face in real, multi-threaded concurrency. If having multiple async operations running at once is not a problem for these methods, you can ignore the reentrancy issues.
2 Block the timer, and wait for running tasks to finish
You can disable the timer, och block the calls to the event handler when you know you have a async task running. You can use a simple state field, or any kind of locking/signaling primitive for this. This makes sure you only have a single operation running at a given time.
3 Cancel any ongoing async operations
If you want to cancel any async operations already running, you can use a cancellationtoken to stop them, and then start a new operation. This is described in this link How to cancel a Task in await?
This would make sense if the operation takes a long time to finish, and you want to avoid spending time to complete an operation that is already "obsolete".
4 Queue the requests
If it's important to actually run all the updates, and you need synchronization you can queue the tasks, and work them off one by one. Consider adding some sort of backpressure-handling if you go down this route...
I want some clarity on this. I know that Task.Delay will internally use a Timer and it is obviously task-based (awaitable), whereas Thread.Sleep will cause the thread to be blocked. However, does calling .Wait on the task cause the thread to be blocked?
If not, one would assume that Task.Delay(2500).Wait() is better than Thread.Sleep(2500). This is slightly different that the SO question/answer here as I'm calling .Wait().
Using Wait on an uncompleted task is indeed blocking the thread until the task completes.
Using Thread.Sleep is clearer since you're explicitly blocking a thread instead of implicitly blocking on a task.
The only way using Task.Delay is preferable is that it allows using a CancellationToken so you can cancel the block if you like to.
Thread.Sleep(...) creates an event to wake you up in X millisec, then puts your Thread to sleep... in X millisec, the event wakes you up.
Task.Delay(...).Wait() creates an event to start a Task in X millisec, then puts your Thread to sleep until the Task is done (with Wait)... in X millisec, the event starts the Task which ends immediately and then wakes you up.
Basically, they are both very similar. The only difference is if you want to wake up early from another Thread, you won't hit the same method.
I want to use Task<> type, but not with TPL, but with .NET4.5/C#async instead.
Thing is, I have some requirements for my case:
I want the task to be run synchronously (some people recommend RunSynchronously(), others Wait(), and others ContinueWith(_, TaskContinuationOptions.ExecuteSynchronously), which one is the adequate here?).
I want the task to run in the same thread (so, not use the threadpool at all).
I want the task to stop after a certain timeout has passed, and throw an exception.
For the latter, I think I need Task.Delay() but I'm not sure how to combine it with the first two requirements.
Thanks
This answer is based on #svick's comment.
I'm going to make the assumption that you want all the "work" of the method to be done on the same thread as the caller, but that you don't mind if a thread pool thread is used for cancellation purposes (I'm assuming this since you mentioned Task.Delay which will use a Timer which will use a thread pool thread when the timer fires.
That said, there would be no need for Task, since when the method returns you would know for certain that the Task was completed. Just a regular method with a timeout will do:
static void DoSomethingOrThrowAfterTimeout(int millisecondsTimeout)
{
CancellationTokenSource cts = new CancellationTokenSource(millisecondsTimeout);
CancellationToken ct = cts.Token;
// do some work
ct.ThrowIfCancellationRequested();
// do more work
ct.ThrowIfCancellationRequested();
// repeat until done.
}
Obviously, with this approach of using cooperative cancellation, the method won't timeout exactly at the timeout, as it will be dependent on how small you can split up the work in the method.
If you want to avoid the usage of another thread (for the CancellationTokenSource), then you could track the starting time and then check how much time has passed (to see if you've exceeded the timeout) at various points in the method (like how ct.ThrowIfCancellationRequested() is used above.
Greetings
I have a program that creates multiples instances of a class, runs the same long-running Update method on all instances and waits for completion. I'm following Kev's approach from this question of adding the Update to ThreadPool.QueueUserWorkItem.
In the main prog., I'm sleeping for a few minutes and checking a Boolean in the last child to see if done
while(!child[child.Length-1].isFinished) {
Thread.Sleep(...);
}
This solution is working the way I want, but is there a better way to do this? Both for the independent instances and checking if all work is done.
Thanks
UPDATE:
There doesn't need to be locking. The different instances each have a different web service url they request from, and do similar work on the response. They're all doing their own thing.
If you know the number of operations that will be performed, use a countdown and an event:
Activity[] activities = GetActivities();
int remaining = activities.Length;
using (ManualResetEvent finishedEvent = new ManualResetEvent(false))
{
foreach (Activity activity in activities)
{
ThreadPool.QueueUserWorkItem(s =>
{
activity.Run();
if (Interlocked.Decrement(ref remaining) == 0)
finishedEvent.Set();
});
}
finishedEvent.WaitOne();
}
Don't poll for completion. The .NET Framework (and the Windows OS in general) has a number of threading primitives specifically designed to prevent the need for spinlocks, and a polling loop with Sleep is really just a slow spinlock.
You can try Semaphore.
A blocking way of waiting is a bit more elegant than polling. See the Monitor.Wait/Monitor.Pulse (Semaphore works ok too) for a simple way to block and signal. C# has some syntactic sugar around the Monitor class in the form of the lock keyword.
This doesn't look good. There is almost never a valid reason to assume that when the last thread is completed that the other ones are done as well. Unless you somehow interlock the worker threads, which you should never do. It also makes little sense to Sleep(), waiting for a thread to complete. You might as well do the work that thread is doing.
If you've got multiple threads going, give them each a ManualResetEvent. You can wait on completion with WaitHandle.WaitAll(). Counting down a thread counter with the Interlocked class can work too. Or use a CountdownLatch.