Search code examples
c#asynchronousasync-awaittask-parallel-librarymanualresetevent

Can Task.Delay cause thread switching?


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.


Solution

  • 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.