Click here to Skip to main content
15,887,214 members
Articles / Web Development
Tip/Trick

Function-A Calling Another Function-B After A Returns

Rate me:
Please Sign up or sign in to vote.
4.50/5 (5 votes)
16 May 2014CPOL3 min read 17.6K   12   3
An introduction to async functions introduced in C# 2012/2013

Introduction

Let’s say there are two functions, Foo1 and Foo2. Foo2 needs to be called after Foo1, and only Foo1 can call Foo2:

Image 1

A realistic scenario might be when Foo1 is invoked using a web service. Foo1 is called and needs to return as quickly as possible so that the calling client doesn’t hang. This means both Foo1 and Foo2 must be asynchronous functions, and that Foo2 must run after Foo1 has returned.

For Foo1 to be able to call Foo2 after Foo1 returns can be done in multiple ways. One way might be to have external queue into which tasks can be inserted so that they can be run when a certain state is set by a separate thread. This is good for scalable enterprise architecture, but seems a bit of an overkill when all we want to do is to call Foo2—after Foo1.

Another way is using the timer object. A third way is using the relatively new ‘async’ method modifier.

The “async” function modifier was introduced in Visual Studio 2012/2013.

Before talking more about the async modifier, here is a complete listing of the code that is also attached to this tip. It's a console application:

C#
using System;

namespace MyCSasync
{
    using System.Threading;
    using System.Threading.Tasks;

    class MyClass
    {
        public static string[] Strings = new string[3];
        public static int Count = 0;

        private async Task Foo2()
        {
            await Task.Yield();

            Strings[Count++] = "Foo2 called at " + DateTime.Now.Ticks;
        }

        public async Task Foo1()
        {
            Strings[Count++] = "Foo1 at " + DateTime.Now.Ticks;

            // Call Foo2 asynchronously AND after this function returns.
            Foo2();

            Strings[Count++] = "End of Foo1 at " + DateTime.Now.Ticks;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyClass myclass = new MyClass();

            myclass.Foo1();

            while (MyClass.Count != 3) Thread.Sleep(1);
            foreach (string msg in MyClass.Strings)
            {
                Console.WriteLine(msg);
            }
        }
    }
} 

While Foo1() is called asynchronously from the Main function, it could be called from a web service method which needs to return back to a client as quickly as possible so the client doesn't seem to hang. Foo2() is a private function that will need to be called after Foo1 completes.

Foo2 is partially executed so that Foo1 can return. This partial execution is just

C#
await Task.Yield()

This allows Foo2 to temporarily exit so that Foo1 can finish. The "Yield" method, as described by Microsoft, "creates an awaitable task that asynchronously yields back to the current context when awaited." That's exactly what we would like to do. There are other ways to do this. Using a delay. The problem with that approach is the behavior of the code may change depending on how fast your computer is. This is easy to test. If you use Task.Delay(1), which is 1 millisecond, it is more than enough to make the code above seem to be behaving the same. If you change the Delay parameter to a TimeSpan object with 1 tick, you may see that the code no longer works as expected.

When you run the code above (ctrl-F5), you should see something similar to:

Image 2

Foo2 is called after Foo1. Note the tick difference, about 20,000. On my machine, that's about 3200th of a second. So a delay of 1 second would seem to work, but certainly not 1 tick. As an exercise, change the code "await Task.Yield()" to "await Task.Delay(1)" and you'll likely see that Foo2 is called after Foo1. Now change it to "await Task.Delay(TimeSpan.FromTicks(1))". You will see that Foo2 is called before "End of Foo1". This is because Foo2's await took less time than Foo1 could return.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
VMAtm20-May-14 20:04
VMAtm20-May-14 20:04 
GeneralRe: My vote of 3 Pin
Erol Esen21-May-14 2:54
Erol Esen21-May-14 2:54 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun4-May-14 22:00
Humayun Kabir Mamun4-May-14 22:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.