What is Synchronous – Method Call

What is Synchronous – Method Call: यदि हम हमारे पिछले उदाहरण Program को ही लें तो Addition() Delegate को Add() Method को Asynchronously Invoke करने का Instruction देने के लिए हमें हमारे पिछले Program के Main() Method को ही निम्नानुसार Modify करना होगा:

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

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

    class InvokingMethodAsyncronously
    {
     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, null, null);

       // Do other work on primary thread...
       Console.WriteLine("Doing more work in Main()!");

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

       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.
Doing more work in Main()!
Add() invoked on thread 3.
10 + 10 is 20.

तो जैसाकि हम इस Program के Output में देख सकते हैं कि इस बार Main() Method Thread ID 1 वाले Thread में Execute हो रहा है जबकि Add() Method के Execution Thread का ID 3 है। यानी दोनों Methods दो अलग Threads में Execute हो रहे हैं।

परिणामस्वरूप इस बार Main() Method, Add() Method के Synchronously Execute होने यानी पूरी तरह से Execute होकर Finish होने का Wait नहीं करता। बल्कि सीधे ही निम्न निम्नानुसार दूसरा Statement Print कर देता है, जो कि Main() Method में ही Specified है:

Doing more work in Main()!

यानी हम देख सकते हैं कि दोनों ही Program के Output में अन्तर है। पहला Program Add() Method को समान Thread में Synchronously Execute कर रहा था। इसलिए निम्नानुसार Output दे रहा था:

Main() invoked on thread 1.
Add() invoked on thread 1.
Doing more work in Main()!
10 + 10 is 20.

जहां Add() Method के पूरी तरह से Execute होने के बाद Main() Method का अगला Statement Run हो रहा था। जबकि हमारे इस Program का Output निम्नानुसार है:

Main() invoked on thread 1.
Doing more work in Main()!
Add() invoked on thread 3.
10 + 10 is 20.

जिसमें Add() Method एक अलग Thread में Invoke होकर Execute होता है, जिसकी वजह से Main() Method का अगला Statement Execute होने के लिए Add*() Method के Execution का Wait नहीं करता।

यानी सरल शब्दों में कहें तो Main() Method व Add() Method दोनों ही दो अलग Threads में Execute हो रहे हैं, इसलिए समान समय पर समानान्तर रूप से Execute हो रहे हैं और Add() Method को Asynchronously Invoke करने के लिए हमने हमारे Main() Method में Addition Delegate के Invoke() Method को निम्नानुसार तरीके से Use किया है, जिसकी वजह से Invoke() Method, Add() Method को एक अलग Thread में Execute करता है:

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

       // Do other work on primary thread...
       Console.WriteLine("Doing more work in Main()!");

       // Obtain the result of the Add() method when ready.
       int answer = b.EndInvoke(iftAR);

इस Code Segment में हमने b नाम का एक Addition Delegate Type का Object Create किया है और इस Delegate Object की Invocation List में Callback Method के रूप में Add नाम Specify करके Add() Method को Delegate Object की Invocation List में Callback Method की तरह Store किया है। ताकि जब Delegate Object को Parenthesis के साथ Specify करके Invoke किया जाए, तो Callback के रूप में Add() Method Execute हो जाए।

फिर हमने निम्न Statement के माध्‍यम से Delegate Object के लिए BeginInvoke() Method को Invoke किया है:

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

परिणामस्वरूप जब Delegate Object Invoke होता है, तो वह Internally Callback Method के रूप में Add() Method को Call करता है तथा उसमें पहले दो Parameters के रूप में Specified मान 10, 10 को Parameter की तरह Pass कर देता है।

फलस्वरूप Add() Method Execute होता है और Parameter के रूप में आने वाले दोनों मानों को जोड देता है तथा 5 Second के लिए Suspended Mode में चला जाता है। साथ ही Execute होने वाले Add() Method के Thread से सम्बंधित विभिन्न Information IAsyncResult Type के iftAR नाम के Reference Variable में Store हो जाता है।

Add() Method द्वारा Return होने वाले मान को प्राप्त करने के लिए हमें हमारे Delegate Object b के लिए EndInvoke() Method को Invoke करना होता है और ये काम हम निम्नानुसार Statement द्वारा करते हैं:

int answer = b.EndInvoke(iftAR);

यानी Add() Method द्वारा Retuned Result हमें तब तक प्राप्त नहीं होताए जब तक कि हम हमारे Delegate Object b के लिए उपरोक्तानुसार EndInvoke() Method को Invoke नहीं करते। परिणामस्वरूप जैसे ही उपरोक्त Statement Execute होता है, Add() Method द्वारा Returned Result answer नाम के Integer Type के Variable में Store हो जाता है, जिसे निम्न Statement द्वारा Output में Print कर दिया जाता है:

Console.WriteLine(“10 + 10 is {0}.”, answer);

लेकिन BeginInvoke() व EndInvoke() के Execution के बीच Add() Method 5 Seconds के लिए Suspended रहता है और ये Suspension केवल Add() Method के Thread में ही होता है, जबकि उसी समय पर Main() Thread Normal तरीके से Run हो रहा होता है।

यानी Suspension का प्रभाव केवल उसी Thread पर होता है, जिस में Add() Method होता है, क्योंकि हमने Add() Method को ही 5 Seconds के लिए Thread.Sleep() Statement द्वारा Suspend किया है।

Synchronizing Calling Thread

पिछले Program में BeginInvoke() व EndInvoke() के बीच 5 Seconds का ही अन्तर है। लेकिन हमारे Main() Method का Code Execute होने में बहुत ही कम समय लगता है। ऐसे में Main() Method फिर से Add() Method के पूरी तरह से Execute होने के लिए Wait करता है, जो कि एक प्रकार से फिर से Synchronous Call को ही Represent करता है।

क्योंकि Main() Thread ही Primary Thread है जो Add() Thread को Invoke कर रहा है और अपना Code Execute करने के बाद Add() Thread के पूरी तरह से Execute होने के लिए Wait कर रहा है, ताकि Add() Method द्वारा Generate होने वाले 10+10 के Result को Console पर Display कर सके। यानी इस तरह का Main() Method Code लिखकर हम फिर से एक प्रकार का Synchronous Call ही Create कर रहे हैं।

निश्चित रूप से यदि Calling Thread किसी भी प्रकार की परिस्थिति में किसी Called Thread द्वारा Block हो जाता है और Called Thread के Complete होने का Wait करता है, तो Asynchronous Delegate का पूरा महत्व ही समाप्त हो जाता है, क्योंकि हम Asynchronous Delegate इसीलिए तो Create करते हैं, ताकि Called Thread, Calling Thread को Block न करे।

इसलिए Calling Thread को इस बात की जानकारी देने के लिए कि Asynchronously Invoked Method पूरी तरह से Execute हो चुका है या नहीं, हम IAsyncResult Interface के IsCompleted Property को Use कर सकते हैं।

इस Property का प्रयोग करके Calling Thread इस बात की जानकारी प्राप्त कर सकता है कि EndInvoke() Method को Invoke करने से पहले Called Thread पूरी तरह से Execute हो चुका है या नहीं।

IsCompleted() Property एक Boolean मान Return करता है। यदि ये Property true Return करता है, तो ये इस बात का संकेत है कि Called Thread पूरी तरह से Execute हो चुका है और उसके द्वारा Returned Result को EndInvoke() को Invoke करके Retrieve किया जा सकता है। जबकि इस Property द्वारा false Return होने का मतलब यही है कि Called Thread अभी भी Running है।

परिणामस्वरूप इस Property को Implement करके हम ऐसा Secondary Thread Create कर सकते हैं, जिसके द्वारा किसी Calling Thread के Block होने की सम्भावना कम से कम होती है। इसलिए इस Property को उपयोग में लेते हुए हम हमारे पिछले Program को ही निम्नानुसार तरीके से फिर से Modify कर सकते हैं:

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

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

    class InvokingMethodAsyncronously
    {
     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, null, null);

       // This message will keep printing until the Add() method is finished.
       while (!iftAR.IsCompleted)
       {
               Console.WriteLine("Doing more work in Main()!");
       	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 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.
Doing more work in Main()!
Add() invoked on thread 3.
Doing more work in Main()!
Doing more work in Main()!
Doing more work in Main()!
Doing more work in Main()!
10 + 10 is 20.

इस Program के Main() Method में हमने निम्नानुसार तरीके से एक Loop के अन्दर IsCompleted Property को Use किया है:

       while (!iftAR.IsCompleted)
       {
               Console.WriteLine("Doing more work in Main()!");
       	Thread.Sleep(1000);
       }

परिणामस्वरूप Main() Method बार-बार IAsyncResult Interface के iftAR Reference Object के IsCompleted property को इस बात की जानकारी प्राप्त करने के लिए Check करता रहता है कि Add() Method ने अपना काम पूरा किया या नहीं।

यदि Add() Method ने अपना काम पूरा नहीं किया होताए तो IsCompleted Property false Return करता है, जिसके Response में हम Loop के अन्दर Specified निम्न Statement को Execute करते हैं:

Console.WriteLine(“Doing more work in Main()!”);

और 1 Second के लिए Main() Thread को Suspend कर देते हैं। 1 Second बाद Main() Thread का यही While Loop फिर से IsCompleted Property को Check करता है और ये प्रक्रिया तब तक चलती रहती है, जब तक कि Add() Method पूरी तरह से Execute नहीं हो जाता।

जैसे ही Add() Method पूरी तरह से Execute हो जाता है, IsCompleted Property true हो जाती है। परिणामस्वरूप while Loop Fail हो जाता है और निम्नानुसार Statement द्वारा Add() Method द्वारा Returned Result को answer नाम के Variable में Store करके Display कर लिया जाता है:

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

इस IsCompleted Property के अलावा IAsyncResult Interface AsyncWaitHandle नाम की एक और Property Provide करता है, जो कि ज्यादा Flexible Waiting Logic लिखने के लिए उपयोगी होता है।

ये Property WaitHandle Type का एक Object Return करता है, जो कि WaitOne() नाम का एक Method Provide करता है। इस WaitHandle.WaitOne() Method का फायदा ये होता है कि हम इस Method द्वारा Waiting के लिए अधिकतम Time Specify कर सकते हैं।

यदि हमारे Specified Time से ज्यादा समय व्‍यतीत हो जाता है, तो WaitOne() Method false Return करता है। इसलिए यदि हम चाहें तो हमारे पिछले Program के While Loop को हम इस Method का प्रयोग करते हुए निम्नानुसार तरीके से भी Specify कर सकते हैं:

       while (!iftAR.AsyncWaitHandle.WaitOne(1000, true))
       {
               Console.WriteLine("Doing more work in Main()!");
       	Thread.Sleep(1000);
       }

हालांकि हम IAsyncResult Interface की इन Properties का प्रयोग करके Calling Thread को Synchronize कर सकते हैं, लेकिन ये Most Efficient तरीका नहीं हैं। क्योंकि कई स्थितियों में IsCompleted Property Continuously false Return करता रहता है। इसलिए Calling Thread को Appropriate Notification Provide करने के लिए हम C# Delegate को कुछ और बेहतर तरीकों से Use कर सकते हैं।

C# BeginInvoke
C# Asynchronous Programming

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

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

BUY NOW GET DEMO REVIEWS