Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Task.Delay cause thread switching? [duplicate]

I have a long running process that sends data to the other machine. But this data is received in chunks (like a set of 100 packets, then delay of minimum 10 seconds).

I started the sending function on a separate thread using Task.Run(() => { SendPackets(); });

The packets to be sent are queued in a Queue<Packet> object by some other function.

In SendPackets() I am using a while loop to retrieve and send (asynchronously) all items available in the queue.

void SendPackets()
{
    while(isRunning)
    {
       while(thePacketQueue.Count > 0)
       {
          Packet pkt = thePacketQueue.Dequeue();

          BeginSend(pkt, callback);   // Actual code to send data over asynchronously
       }

       Task.Delay(1000);  // <---- My question lies here
    }
 }

All the locks are in place!

My question is, when I use Task.Delay, is it possible then the next cycle may be executed by a thread different from the current one?

Is there any other approach, where instead of specifying delay for 1 second, I can use something like ManualResetEvent, and what would be the respective code (I have no idea how to use the ManualResetEvent etc.

Also, I am new to async/await and TPL, so kindly bear with my ignorance.

TIA.

like image 434
Manish Dalal Avatar asked Mar 06 '20 08:03

Manish Dalal


People also ask

Does task delay create a new thread?

Task. Delay does not create new Thread, but still may be heavy, and no guaranties on order of execution or being precise about deadlines.

Does task delay block the thread?

Delay(1000) doesn't block the thread, unlike Task. Delay(1000). Wait() would do, more details.

What does Task delay do C#?

Delay(Int32) Creates a task that completes after a specified number of milliseconds.

Does task delay start immediately?

@Lyrk Yes, the timer starts the moment you create taskDelay . If you await the task after doing, say, two seconds worth of other work, await would return after one second.


1 Answers

My question is, when I use Task.Delay, is it possible then the next cycle may be executed by a thread different from the current one?

Not with the code you've got, because that code is buggy. It won't actually delay between cycles at all. It creates a task that will complete in a second, but then ignores that task. Your code should be:

await Task.Delay(1000);

or potentially:

await Task.Delay(1000).ConfigureAwait(false);

With the second piece of code, that can absolutely run each cycle on a different thread. With the first piece of code, it will depend on the synchronization context. If you were running in a synchronization context with thread affinity (e.g. you're calling this from the UI thread of a WPF or WinForms app) then the async method will continue on the same thread after the delay completes. If you're running without a synchronization context, or in a synchronization context that doesn't just use one thread, then again it could run each cycle in a different thread.

As you're starting this code with Task.Run, you won't have a synchronization context - but it's worth being aware that the same piece of code could behave differently when run in a different way.

As a side note, it's not clear what's adding items to thePacketQueue, but unless that's a concurrent collection (e.g. ConcurrentQueue), you may well have a problem there too.

like image 127
Jon Skeet Avatar answered Oct 18 '22 00:10

Jon Skeet