When C# Anonymous Method is Asynchronously Invoked

C# is pretty flexible in syntax which by means of working with delegate or lambda expression allows one to define subroutine logic within the argument list of a method call where it is passed.

It is really cool, though it's still not clear whether C# directly or indirectly supports (probably not) defining a class in such a way which is pretty much a feature supposed to be seen in dynamic languages (not sure whether Java has it).

This feature not only saves time and writing of code, it also guarantees thread safety which is obviously the result of C# designer having taken into consideration the fact that this is the situation where most of delegated callbacks coded in this manner are supposed to be used.

Let's look at the following code snippet as an example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace AsyncCallOnDele
{
    class Program
    {
        class AsyncCaller : IDisposable
        {
            List<Thread> _threads = new List<Thread>();

            class ThreadUserData
            {
                public AsyncCallerCallback Callback;
                public object Arg;

                public ThreadUserData(AsyncCallerCallback callback, object arg)
                {
                    Callback = callback;
                    Arg = arg;
                }
            }

            public void ThreadProcedure(object arg)
            {
                ThreadUserData ud = (ThreadUserData)arg;
                ud.Callback(ud.Arg);
            }

            public void BeginInvoke(AsyncCallerCallback callback, object arg)
            {
                Thread thread = new Thread(new ParameterizedThreadStart(ThreadProcedure));
                thread.Start(new ThreadUserData(callback, arg));
                _threads.Add(thread);
            }
            public void Dispose() { 
                foreach (Thread thread in _threads)                    
                thread.Join(); 
            }
 
        }

        public delegate object AsyncCallerCallback(object o);

        class WorkData
        {
            public int Value;
        }

        static void Main(string[] args)
        {
            AsyncCaller cc = new AsyncCaller();

            int count = 100;
            WorkData[] wdList = new WorkData[count];

            using (AsyncCaller ac = new AsyncCaller())
            {
                for (int i = 0; i < count; i++)
                {
                    int localValue = i * 3;
                    wdList[i] = new WorkData();
                    ac.BeginInvoke(o =>
                    {
                        WorkData wd = (WorkData)o;
                        lock (wdList)
                        {
                            Thread.Sleep(50);   // a chance for 'localValue' to change
                            wd.Value = localValue;
                        }
                        return null;
                    }, wdList[i]);
                }
            }  // here it waits until all threads complete within the Dispose method
            foreach (WorkData wd in wdList)
            {
                Console.WriteLine("{0} ", wd.Value);
            }
        }
    }
}

 

The output of the program is a list of integer values which are expected to be from 0 to 297 with a constant increment of 3 and they are.

I originally suspected they wouldn't give this result, an obvious influence by traditional C/C++ mindset. But after thinking about it again, I found it quite reasonable to have thing like this in C#, as such modern languages as C# and Java were designed to be as thread safe as they could.

So with this feature provided this way, the develop can focus their mind on the logic and design without worrying about isolating the variables accessed from the nested anonymous delegates in a multi-thread context.

 

 

 

 

 

 

 

你可能感兴趣的:(When C# Anonymous Method is Asynchronously Invoked)