C# Asynchronous Programming

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW DOWNLOAD READ ONLINE

AsyncCallback Delegate

Calling Thread द्वारा बार-बार Secondary Thread के IsCompleted Property को इस बात के लिए Check करना कि Secondary Thread Complete हो गया है या नहीं] की तुलना में ज्यादा बेहतर तरीका यही है कि Secondary Method स्वयं इस बात की Information Calling Thread को दे दे कि उसने अपना काम Finish कर लिया है और उसके द्वारा Generated Result को Calling Thread Access कर सकता है।

जब हम Called Thread से इस प्रकार का Behavior चाहते हैं तब हमें BeginInvoke() Method में System.AsyncCallback Delegate के एक Instance को Parameter की तरह Pass करना होता है, जिसे हमने पिछले Program तक null Specify किया था।

परिणामस्वरूप जब हम BeginInvoke() Method में AsyncCallback Object को Specify करते हैं, तो ये Delegate Object Specify किए गए Method को उस समय Automatically Invoke कर देता है, जब Called Thread का काम पूरी तरह से Finish हो चुका होता है।

यहां ध्‍यान देने वाली बात ये है कि जब हम इस तरह से AsyncCallback Parameter Pass करते हैं, तो Callback Method हमेंशा Secondary Thread पर Call होता है, Primary Thread पर नहीं और इस प्रक्रिया का महत्वपूर्ण प्रभाव हमें तब देखने को मिलता है, जब हम WPF या Windows Forms का प्रयोग करते हुए Graphical User Interface Create करते हैं। क्योंकि विभिन्न Controls Thread-Affinity में होते हैं। यानी सभी Controls केवल उसी Thread द्वारा Handle हो सकते हैं, जिसने उन्हें Create किया है।

किसी भी अन्‍य Delegate की तरह ही AsyncCallback Delegate भी केवल Matching Pattern या Signature वाले Methods को ही Invoke कर सकता है। इसलिए हमारे उपरोक्त उदाहरण के अनुसार AsyncCallback Delegate का Signature निम्नानुसार है, जिसमें IAsyncResult Type का केवल एक Parameter Pass किया जा रहा है:

void MyAsyncCallbackMethod(IAsyncResult itfAR)

मानलो कि हमारे पास एक और Console Application है जो कि Addition Delegate को Use कर रहा है। लेकिन इस बार हम Main() Method द्वारा इस बात का पता नहीं लगा रहे हैं, कि Secondary Thread Complete हुआ या नहीं।

बल्कि इस बार हमारा Secondary Thread ही इस बात की Information देता है कि उसका काम समाप्त हो गया है और इस बात की Information देने के लिए वह Callback के रूप में AddComplete() नाम के Method को Invoke करता है। यानी AddComplete() Method का Invoke होना इसी बात का Indication है कि Thread द्वारा Add करने का काम समाप्त हो चुका है। जैसे:

File Name: AsyncCallbackDelegate.cs
using System;
using System.Threading;

namespace CSharpMultiThreading
{
    public delegate int Addition(int x, int y);

    class InvokingMethodAsyncronously
    {
        private static bool isDone = false;
        static void Main(string[] args)
        {
            // Print out the ID of the executing thread.
            Console.WriteLine("Main() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);

            // Invoke Add() on a secondary thread.
            Addition b = new Addition(Add);
            IAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), null);

            // This message will keep printing until the Add() method is finished.
            while (!isDone)
            {
                Console.WriteLine("Working...");
                Thread.Sleep(1000);
            }

            // Obtain the result of the Add() method when ready.
            int answer = b.EndInvoke(iftAR);
            Console.WriteLine("10 + 10 is {0}.", answer);
        }

        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");
            isDone = true;
        }

        static int Add(int x, int y)
        {
            // Print out the ID of the executing thread.
            Console.WriteLine("Add() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);

            // Pause to simulate a lengthy operation.
            Thread.Sleep(5000);
            return x + y;
        }
    }
}

// Output:
   Main() invoked on thread 1.
   Working...
   Add() invoked on thread 3.   
   Working...
   Working...
   Working...
   Working...
   Working...
   AddComplete() invoked on thread 3.
   Your addition is complete
   10 + 10 is 20.

जब ये Program Run होता है, तो सबसे पहले निम्न Statement द्वारा b नाम का एक Addition Type का Delegate Object Create किया जाता है:

Addition b = new Addition(Add);

और इस Delegate Object के लिए BeginInvoke() Method को निम्नानुसार तरीके से Invoke किया जाता है:

IAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), null);

जैसाकि इस Statement के BeginInvoke() Method में हम देख सकते हैं कि तीसरे Parameter के रूप में हमने AsyncCallback Delegate Type का एक नया Object Create किया है और इस Asynchronous Delegate Object में Parameter के रूप में AddComplete Method के नाम को Specify किया है। परिणामस्वरूप जब Delegate Object b के लिए BeginInvoke() Method को Invoke किया जाता है, तो इस Method के पहले दो Arguments Add() Method में Parameter की तरह Pass हो जाते हैं, जो कि इन्हें जोडने का काम करता है।

लेकिन चूंकि हम ये मान रहे हैं कि Add() Method को बहुत ज्यादा काम करना होता है, जिसकी वजह से हमें पता नहीं होता कि वह काम कब पूरा होगा। इसलिए हमने तीसरे Parameter के रूप में AddComplete नाम के Callback Method को Specify कर दिया है।

ये Method Exactly तभी Execute होता है, जब Add() Method पूरी तरह से Execute हो चुका होता है, क्योंकि हमने इस Method को AsyncCallback Type के Delegate Object की Invocation List में Add किया है, जो कि Add() Method के पूरी तरह से Execute होने के बाद ही Execute होता है।

फलस्वरूप इस बार Main() Method में इस बात को Check नहीं किया जा रहा है कि Add() Method का Execution Complete हुआ या नहीं बल्कि इस बार Add() Method स्वयं Complete होने के बाद AddComplete Method को Invoke करके इस बात का Indication देता है कि Add() Method का Execution पूरी तरह से Complete हो गया है।

परिणामस्वरूप AddComplete() Method जब तक Execute नहीं होताए तब तक Main() Method निम्नानुसार तरीके से isDone Property को true Value के लिए Check करता रहता है:

            while (!isDone)
            {
                Console.WriteLine("Working...");
                Thread.Sleep(1000);
            }

यानी जब तक isDone Field का मान true नहीं हो जाताए तब तक ये while Loop चलता रहता है और Output में “Working…” Message Display करता रहता है। जबकि isDone का मान तब तक true नहीं होताए जब तक कि AddComplete() नाम का निम्नानुसार Defined Method Execute नहीं होता:

        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");
            isDone = true;
        }

और AddComplete() नाम का Method तब तक Execute नहीं होताए जब तक कि BeginInvoke() Method द्वारा Invoked Add() Method पूरी तरह से Execute नहीं हो जाता।

इस प्रकार से हम AsyncCallback Delegate Object का प्रयोग करके Called Thread द्वारा इस बात का Notification Trigger करते हैं कि Called Thread ने अपना काम Complete कर लिया है, जो कि पिछले उदाहरणों द्वारा Use किए गए विभिन्न तरीकों से ज्यादा बेहतर व Perfect तरीका है।

AsyncResult Class

यदि हम पिछले Program को देखें तो AddComplete() नाम का Callback Method दो संख्‍याओं को जोडने के Actual Operation द्वारा Generate हो रहे Result को Print नहीं कर रहा है। बल्कि केवल Main() Method को इस बात का Instruction देने का काम कर रहा है कि Add() Method ने अपना काम पूरी तरह से Finish कर लिया है। क्योंकि AsyncCallback Delegate Object का Target (AddComplete() Method)] Main() Method के Scope में Created Addition Delegate के Object b को Access नहीं कर सकता।

जिसकी वजह से हम AddComplete() Method के अन्दर EndInvoke() Method को Call नहीं कर सकते, क्योंकि यदि हम EndInvoke() Method को AddComplete() Method में Use करना चाहें, तो हमारा AddComplete() Method कुछ निम्नानुसार होगा:

        static void AddComplete(IAsyncResult itfAR)
        {
            . . .

            int answer = b.EndInvoke(iftAR);
            Console.WriteLine("10 + 10 is {0}.", answer);
        }

जहां हम Addition Delegate Object b को EndInvoke() Method के साथ Use करने की कोशिश करेंगे, जो कि AddComplete() Method के Scope में Exist नहीं है।

हालांकि यदि हम Addition Delegate Object को static Keyword के साथ Specify करके उसे Main() व AddComplete() दोनों Methods में समान रूप से Use करते हुए ऐसा कर सकते हैं। लेकिन एक ज्यादा बेहतर तरीका ये है कि हम EndInvoke() Method में Incoming Parameter के रूप में Pass किए जाने वाले IAsyncResult Parameter को Reuse करें।

AsyncCallback Delegate Object के Target (AddComplete() Method) में Pass किया जाने वाला IAsyncResult Type का Incoming Parameter वास्तव में AsyncResult Class का Instance Object है, जिसे System.Runtime.Remoting.Messaging Namespace में Define किया गया है। जिसकी AsyncDelegate Property उस Original Asynchronous Delegate के Actual Reference को Return करता है, जिसे कहीं और Declare किया गया है।

यानी यदि हम AddComplete() Method में Parameter के रूप में आने वाले AsyncResult Type के Object के साथ AsyncDelegate Property को Use करें, तो हमें AddComplete() Method में Main() Method के Addition Delegate Object b का Reference प्राप्त हो जाएगा, जिसके साथ हम EndInvoke() Method को Invoke कर सकते हैं।

लेकिन हम इस Incoming Reference के साथ Directly AsyncDelegate Property को Use नहीं कर सकते। क्योंकि आने वाला Parameter एक IAsyncResult जो कि एक Interface है, के Reference Variable में Stored है। इसलिए पहले हमें इस Interface Reference से Object Reference को अलग करने के लिए इसे System.Object Type में Cast करना होगा।

परिणामस्वरूप जो Converted Reference Return होगा, वह AsyncResult Class Type का Reference होगा, जिसके साथ हम AsyncDelegate Property को Use कर सकते हैं। यदि हम इस Concept को अपने पिछले Program पर Apply करना चाहें, तो हमारा Modified Program कुछ निम्नानुसार बनेगा:

File Name: AsyncResultClass.cs
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace CSharpMultiThreading
{
    public delegate int Addition(int x, int y);

    class InvokingMethodAsyncronously
    {
        private static bool isDone = false;

        static void Main(string[] args)
        {
            // Print out the ID of the executing thread.
            Console.WriteLine("Main() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);

            // Invoke Add() on a secondary thread.
            Addition b = new Addition(Add);
            IAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), null);

            while (!isDone)
            {
                Console.WriteLine("Working...");
                Thread.Sleep(1000);
            }
        }

        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");

            // Now get the result.
            AsyncResult ar = (AsyncResult)itfAR;
            Addition b = (Addition)ar.AsyncDelegate;
            Console.WriteLine("10 + 10 is {0}.", b.EndInvoke(itfAR));
            isDone = true;
        }

        static int Add(int x, int y)
        {
            // Print out the ID of the executing thread.
            Console.WriteLine("Add() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);

            // Pause to simulate a lengthy operation.
            Thread.Sleep(5000);
            return x + y;
        }
    }
}

Output:
Main() invoked on thread 1.
Working...
Add() invoked on thread 3.
Working...
Working...
Working...
Working...
Working...
AddComplete() invoked on thread 3.
Your addition is complete
10 + 10 is 20.

इस बार भी हमें वही Output प्राप्त होता है, जो पिछले Program से प्राप्त हुआ था। लेकिन इस बार हमने EndInvoke() Method को AddComplete() नाम के Callback Method के अन्दर ही Call कर लिया है और ऐसा करने के लिए हमने हमारे AddComplete() Method को कुछ निम्नानुसार तरीके से Modify किया है:

        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.", Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");

            // Now get the result.
            AsyncResult ar = (AsyncResult)itfAR;
            Addition b = (Addition)ar.AsyncDelegate;
            Console.WriteLine("10 + 10 is {0}.", b.EndInvoke(itfAR));
            isDone = true;
        }

जैसाकि इस Method में हम देख सकते हैं कि हमने इस Method में Argument के रूप में आने वाले IAsyncResult Interface Type के Reference Variable से निम्नानुसार Casting करके AsyncResult Class Type के Reference Variable को Initialize किया है:

AsyncResult ar = (AsyncResult)itfAR;

और फिर Addition Delegate Type का एक Object Create करके AsyncResult Type के Reference से Addition Delegate Type के Object को Cast किया है, ताकि हम Addition Delegate Type के Object के लिए EndInvoke Method को Call कर सकें।

Custom State Data Transaction

Asynchronous Delegate का ये Final Aspect है जिसमें हमें BeginInvoke() Method के चौथे Parameter के बारे में समझना होता है, जिसे अभी तक के सभी Programs में हमने null Assign किया था। ये Parameter हमें Primary Thread से Callback Method को Additional State Data Pass करने की सुविधा Provide करता है। चूंकि ये Argument एक System.Object Type का Parameter Accept करता है, इसलिए हम इस Parameter में किसी भी प्रकार का Data Pass कर सकते हैं।

उदाहरण के लिए मानलो कि हम Primary Thread के माध्‍यम से AddComplete() Method में Custom Text Message Pass करना चाहते है। इस जरूरत को पूरा करने के लिए हम BeginInvoke() Method के चौथे Parameter का प्रयोग करते हुए निम्नानुसार एक Program Create कर सकते हैं:

File Name: BeginInvokeWithAllParameters.cs
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;

namespace CSharpMultiThreading
{
    public delegate int Addition(int x, int y);

    class InvokingMethodAsyncronously
    {
        private static bool isDone = false;

        static void Main(string[] args)
        {
            // Print out the ID of the executing thread.
            Console.WriteLine("Main() invoked on thread {0}.", Thread.CurrentThread.ManagedThreadId);

            // Invoke Add() on a secondary thread.
            Addition b = new Addition(Add);
            IAsyncResult iftAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), "Main() Method is being Over Now.");

            while (!isDone)
            {
                Console.WriteLine("Working...");
                Thread.Sleep(1000);
            }
        }

        static void AddComplete(IAsyncResult itfAR)
        {
            Console.WriteLine("AddComplete() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine("Your addition is complete");

            // Now get the result.
            AsyncResult ar = (AsyncResult)itfAR;
            Addition b = (Addition)ar.AsyncDelegate;
            string msg = (string)itfAR.AsyncState;
            Console.WriteLine("10 + 10 is {0}.\n{1}", b.EndInvoke(itfAR), msg);
            isDone = true;
        }

        static int Add(int x, int y)
        {
            // Print out the ID of the executing thread.
            Console.WriteLine("Add() invoked on thread {0}.", 
	Thread.CurrentThread.ManagedThreadId);

            // Pause to simulate a lengthy operation.
            Thread.Sleep(5000);
            return x + y;
        }
    }
}

Output:
Main() invoked on thread 1.
Working...
Add() invoked on thread 3.
Working...
Working...
Working...
Working...
Working...
AddComplete() invoked on thread 3.
Your addition is complete
10 + 10 is 20.
Main() Method is being Over Now.

इस Program में हमने निम्नानुसार Main() Method में Change करके BeginInvoke() Method को चौथा Parameter Pass किया है:

IAsyncResult iftAR = b.BeginInvoke(10, 10,new AsyncCallback(AddComplete),”Main() Method is being Over Now.”);

और इस Message को AddComplete() Method में Retrieve करने के लिए निम्नानुसार AddComplete Method के दो Statements को Change किया है:

string msg = (string)itfAR.AsyncState;
Console.WriteLine(“10 + 10 is {0}.\n{1}”, b.EndInvoke(itfAR), msg);

परिणामस्वरूप जब हम इस Program को Run करते हैं, तो हमें उपरोक्तानुसार Output प्राप्त होता है। क्योंकि AddComplete() Method Execute होते समय AsyncState Property के माध्‍यम से BeginInvoke() Method के चौथे Parameter के रूप में आने वाले Text को एक String Object में Store करके Console में Display कर देता है।

इस तरह से C# के Delegates के Synchronous व Asynchronous Methods को Invoke करने की Capability को समझने के बाद अब हम इस स्थिति में हैं कि .NET Supported Multi-Threaded Applications Create करने के लिए .NET द्वारा Provided अन्‍य Features को समझ सकें।

What is Synchronous - Method Call
C# Thread Sleep

C# in Hindiये Article इस वेबसाईट पर Selling हेतु उपलब्‍ध EBook C#.NET in Hindi से लिया गया है। इसलिए यदि ये Article आपके लिए उपयोगी रहा, तो निश्चित रूप से ये पुस्तक भी आपके लिए काफी उपयोगी साबित होगी। 

C#.NET in Hindi | Page:908 | Format: PDF

BUY NOW DOWNLOAD READ ONLINE

Download All Hindi EBooks

सभी हिन्दी EBooks C, C++, Java, C#, ASP.NET, Oracle, Data Structure, VB6, PHP, HTML5, JavaScript, jQuery, WordPress, etc... के DOWNLOAD LINKS प्राप्‍त करें, अपने EMail पर।

Register करके Login करें। इस Popup से छुटकारा पाएें।