0

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)

Bercovici Adrian
  • 8,794
  • 17
  • 73
  • 152
  • I would be careful here, Thread.Sleep usually would indicate that you are waiting for some other thing to complete, unless that other thing is deterministic (in dot net probably not) this can introduce bugs. Or you would end up pausing your thread for longer than necessary (to avoid waking it earlier than necessary. Have a look at this https://blogs.msmvps.com/peterritchie/2007/04/26/thread-sleep-is-a-sign-of-a-poorly-designed-program/ – peeyush singh Apr 24 '19 at 07:07
  • I was leaning to `Task.Delay`.Is there any problem with it ?I just want to pause the execution of the following code for a defined period of time. – Bercovici Adrian Apr 24 '19 at 07:13

3 Answers3

1

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.

Rain336
  • 1,450
  • 14
  • 21
  • "Thread.Sleep would send a thread from dot net threadpool to sleep". Isn't the work of Sleep to send the current thread to sleep (irrespective of being a threadpool thread). – peeyush singh Apr 24 '19 at 07:10
  • `Thread.Sleep` sets the current Thread to sleep, but an async method might be scheduled on a Thread from the .NET Thread Pool in which case it would be set to sleep. – Rain336 Apr 24 '19 at 07:14
  • So basically the thread executing UpdateAsync would be put to sleep in both cases? – peeyush singh Apr 24 '19 at 07:18
  • Yes but `Thread.Sleep` wouldn't notify the TaskScheduler and therefor it thinks the Thread is still busy executing your method. – Rain336 Apr 24 '19 at 07:34
1

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.

noseratio
  • 59,932
  • 34
  • 208
  • 486
  • Well i do not care if it is a `Task` or a `Thread` as long as it is decoupled from the `Main thread`.The fact that its execution gets done by different threads(`Threadpool`) does not bother me as long as in its execution there's a logical pause at every iteration.This `Task/Thread` will act as a background worker and will have the scope of the application. – Bercovici Adrian Apr 24 '19 at 09:03
  • 2
    @BercoviciAdrian, why do you start a thread then? You could just do something like `await Task.Delay(REFRESH_INTERVAL).ConfigureAwait(false)` as a first statement of `UpdateAsync`. – noseratio Apr 24 '19 at 09:14
  • Well it is an infinite loop.I could place it in a `Task` as well then can't i? – Bercovici Adrian Apr 24 '19 at 09:15
  • 1
    @BercoviciAdrian yes you can and you already do, inside `UpdateAsync`. – noseratio Apr 24 '19 at 09:24
  • 1
    You'd only need to offload an async method to another thread (usually with `Task.Run`) if you have a CPU-intensive or blocking code inside the async method. And normally, that would only be a concern if you invoke an async method like that on a UI thread. – noseratio Apr 24 '19 at 09:24
  • So there is no problem with using `Task.Run` for a `Task` that runs for the entire scope of the application.I thought that in this case i should just use a `Thread`. – Bercovici Adrian Apr 24 '19 at 09:33
  • 1
    @BercoviciAdrian, no problem at all, IMO that'd be the right way. Just pay attention to exception handling/logging, depending on the nature of that task. Search SO for "Task + fire-and-forget", it appears to be your scenario. – noseratio Apr 24 '19 at 09:37
0

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.

Marco Salerno
  • 5,131
  • 2
  • 12
  • 32