Search code examples
c#.netmultithreading

Why does the callback/endinvoke happen after all begin invokes called?


What I'm trying to do is queue up a big list of similar tasks. The time it takes each task to complete is small but there are a lot of them. For each item in the list, I create a delegate and call the delegate.BeginInvoke method then I move to creating the next one.

I would expect in the below example that I would get at least one "****** End Invoke ****" to occur BEFORE all of the begin invokes are called. Instead, it looks like the compiler is starting all of my begin invokes before any end invokes are received.

Is this normal behavior? Is there another way I can send off a task/method on another thread and receive it back while continuing to spur up more tasks?

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

namespace AsyncResultTesting
{
    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("Starting");
            for (int i = 0; i < 100; i++)
            {
                delMeth d = new delMeth(sleepMethod);
                Console.WriteLine(string.Format("Calling the begin invoke from thread: {0} for ID: {1}", Thread.CurrentThread.ManagedThreadId.ToString(), i.ToString()));
                IAsyncResult ar = d.BeginInvoke(i, callbackMessage, d);
            }
            Console.ReadLine();
        }

        private delegate int delMeth(int id);

        private static int sleepMethod(int id)
        {
            Console.WriteLine(Environment.NewLine + String.Format("Thread: {0} is sleeping. Delegate id is {1}", Thread.CurrentThread.ManagedThreadId.ToString(),id.ToString()));
            Console.WriteLine(String.Format("Thread Properties IsThreadPoolThread? = {0} isThreadBackground? = {1} ThreadState: = {2}", Thread.CurrentThread.IsThreadPoolThread.ToString(), Thread.CurrentThread.IsBackground.ToString(), Thread.CurrentThread.ThreadState.ToString()));
            Console.WriteLine("");
            Thread.Sleep(100);              
            return id;

        }

        private static void callbackMessage(IAsyncResult ar)
        {
            delMeth d = (delMeth)ar.AsyncState;
            int result = d.EndInvoke(ar);
            Console.WriteLine(Environment.NewLine + "************************ END INVOKE *****************************");
            Console.WriteLine(String.Format("Delegate was just called back for id: {0}", result.ToString()));
        }

    }


}

Unfortunately I have to design this using .NET 3.5 so Task Asynchronous Processing is not available to me.


Solution

  • USR is correct. Everything is functioning how I would expect it to. If i sleep for 10 ms then I see EndInvokes come back in the middle of BeginInvokes.

    Thanks USR.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Threading;
    
    namespace AsyncResultTesting
    {
        class Program
        {
    
            static void Main(string[] args)
            {
                Console.WriteLine("Starting");
    
    
    
                for (int i = 0; i < 150; i++)            {
                    delMeth d = new delMeth(sleepMethod);
                    Console.WriteLine(string.Format("Calling the begin invoke from thread: {0} for ID: {1}", Thread.CurrentThread.ManagedThreadId.ToString(), i.ToString()));
                    IAsyncResult ar = d.BeginInvoke(i, new AsyncCallback(callbackMessage), d);
                }
                Console.ReadLine();
            }
    
            private delegate int delMeth(int id);
    
            private static int sleepMethod(int id)
            {
                Console.WriteLine(Environment.NewLine + String.Format("Thread: {0} is sleeping. Delegate id is {1}", Thread.CurrentThread.ManagedThreadId.ToString(),id.ToString()));
                Console.WriteLine(String.Format("Thread Properties IsThreadPoolThread? = {0} isThreadBackground? = {1} ThreadState: = {2}", Thread.CurrentThread.IsThreadPoolThread.ToString(), Thread.CurrentThread.IsBackground.ToString(), Thread.CurrentThread.ThreadState.ToString()));
                Console.WriteLine("");
                Thread.Sleep(10);              
                return id;
    
            }
    
            private static void callbackMessage(IAsyncResult ar)
            {
                delMeth d = (delMeth)ar.AsyncState;
                int result = d.EndInvoke(ar);
                Console.WriteLine(Environment.NewLine + "************************ END INVOKE *****************************");
                Console.WriteLine(String.Format("Delegate was just called back for id: {0}", result.ToString()));
            }
    
        }
    
    
    }