September 8, 2024

Thread.Delay() -- a third look at async/await

The following does work. Hooray! There is nothing like learning by rolling up your sleeves and getting your hands dirty.
using System;
using System.Threading.Tasks;

namespace Example
{
    public class Wally
    {
        public static int Delay { private get; set; }

		public static async Task new_wait ( string msg )
        {
            await Task.Delay ( Delay );
            Console.WriteLine ( msg );
        }


        public static void chat ( string msg, int repeat )
        {
            for ( int i=0; i<repeat; i++ ) {
                Task task = Wally.new_wait ( msg );
                task.Wait ();
            }
        }

    }
}

namespace HogHeaven
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Example.Wally.Delay = 1000;
            Example.Wally.chat ( "Kilroy is here !!", 4 );
            Console.WriteLine ( "All done" );
        }
    }
}
// THE END
The action now is in the new_wait() method. Notice that we have moved the call to WriteLine() here. It is now located in the "last half" of the async method so that it will run after Task.Delay finishes. Also notice that new_wait() returns a Task object. This is so we can handle the execution thread that returns immediately when we make the await() call. (If this dicussion is unclear, go back to the prior example that did not work and read the discussion). The loop in chat() now waits here, which means that it is more or less pointless (other than our education) to do all this async/await business. Other code (notable GUI applications) would have plenty of other things to do, and an event loop that the code would return to. All of that requires more education about C# tasks.

Notice that the C# compiler does quite a bit of magic involving the async routine "new_wait()". It captures the last half of the routine to run later along with its variables and environment. The literature calls this package a continuation, but it is effectively a sort of "closure" if you are familiar with that lingo from other languages.

There is one difference here between this and the previous working program. The last Kilroy message and the final "All done" have no time delay between them.

If we get rid of the task.Wait() the system will schedule all four Task.Delay() continuations, pretty much all at once, then exit before any of them finish. In fact I tried this, and indeed the only output from the program is "All done".

Reading assignments

The first of the above links is an epic lecture on this whole business. You should at least look at it.


Feedback? Questions? Drop me a line!

Tom's Computer Info / [email protected]