SynchronizationContext क्या करता है?


135

पुस्तक प्रोग्रामिंग सी # में, इसके बारे में कुछ नमूना कोड है SynchronizationContext:

SynchronizationContext originalContext = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(delegate {
    string text = File.ReadAllText(@"c:\temp\log.txt");
    originalContext.Post(delegate {
        myTextBox.Text = text;
    }, null);
});

मैं सूत्र में एक शुरुआत कर रहा हूं, इसलिए कृपया विस्तार से उत्तर दें। पहले, मुझे नहीं पता कि संदर्भ का क्या मतलब है, कार्यक्रम में क्या बचत है originalContext? और जब Postविधि निकाल दी जाती है, तो UI थ्रेड क्या करेगा?
अगर मैं कुछ मूर्खतापूर्ण बातें पूछूं, तो कृपया मुझे सुधार दें, धन्यवाद!

संपादित करें: उदाहरण के लिए, यदि मैं सिर्फ myTextBox.Text = text;विधि में लिखता हूं , तो क्या अंतर है?


1
यह कहने के लिए ठीक मैनुअल में यह है कि इस वर्ग द्वारा कार्यान्वित सिंक्रोनाइज़ेशन मॉडल का उद्देश्य सामान्य लैंग्वेज रनटाइम के आंतरिक एसिंक्रोनस / सिंक्रोनाइज़ेशन संचालन को अलग-अलग सिंक्रोनाइज़ेशन मॉडल के साथ ठीक से व्यवहार करने की अनुमति देना है। यह मॉडल कुछ आवश्यकताओं को भी सरल करता है जो प्रबंधित अनुप्रयोगों को अलग-अलग सिंक्रनाइज़ेशन वातावरण के तहत सही ढंग से काम करने के लिए पालन करना पड़ा है।
ta.speot.is

IMHO async पहले से ही इंतजार कर रहा है
रॉय नामी

7
@RoyiNamir: हाँ, लेकिन लगता है क्या: async/ नीचे awaitपर निर्भर करता SynchronizationContextहै।
stakx - अब

जवाबों:


170

SynchronizationContext क्या करता है?

सीधे शब्दों में, SynchronizationContextएक स्थान का प्रतिनिधित्व करता है "जहां" कोड निष्पादित हो सकता है। इसके स्थान Sendया Postविधि से पारित होने वाले प्रतिनिधि तब उस स्थान पर आमंत्रित किए जाएंगे। ( Postगैर-अवरोधक / अतुल्यकालिक संस्करण है Send)

हर धागे SynchronizationContextके साथ एक उदाहरण जुड़ा हो सकता है। रनिंग थ्रेड को स्थैतिक SynchronizationContext.SetSynchronizationContextविधि को कॉल करके एक सिंक्रनाइज़ेशन संदर्भ के साथ जोड़ा जा सकता है , और चल रहे थ्रेड के वर्तमान संदर्भ को SynchronizationContext.Currentसंपत्ति के माध्यम से क्वेर किया जा सकता है

मैंने जो कुछ भी लिखा है उसके बावजूद (प्रत्येक थ्रेड में एक संबंधित सिंक्रनाइज़ेशन संदर्भ है), SynchronizationContextजरूरी नहीं कि एक विशिष्ट थ्रेड का प्रतिनिधित्व करता है ; यह कई थ्रेड्स (जैसे कि एक ThreadPoolवर्कर थ्रेड), या किसी विशिष्ट CPU कोर , या यहां तक ​​कि किसी अन्य नेटवर्क होस्ट तक किसी भी थ्रेड्स में भेजे गए प्रतिनिधियों के आमंत्रण को भी अग्रेषित कर सकता है । जहां आपके प्रतिनिधि समाप्त हो रहे हैं वे SynchronizationContextउपयोग किए गए प्रकार पर निर्भर हैं ।

विंडोज फॉर्म WindowsFormsSynchronizationContextउस थ्रेड पर स्थापित होगा जिस पर पहला फॉर्म बनाया गया है। (इस थ्रेड को आमतौर पर "यूआई थ्रेड" कहा जाता है।) इस प्रकार का सिंक्रोनाइज़ेशन संदर्भ बिल्कुल उस थ्रेड पर पास किए गए प्रतिनिधियों को आमंत्रित करता है। यह विंडोज फॉर्म के बाद से बहुत उपयोगी है, कई अन्य यूआई फ्रेमवर्क की तरह, केवल उसी धागे पर नियंत्रण के हेरफेर की अनुमति देता है जिस पर वे बनाए गए थे।

क्या होगा अगर मैं सिर्फ myTextBox.Text = text;विधि में लिखूं , क्या अंतर है?

आपके द्वारा पास किया गया कोड ThreadPool.QueueUserWorkItemथ्रेड पूल वर्कर थ्रेड पर चलाया जाएगा। यही है, यह उस थ्रेड पर निष्पादित नहीं करेगा जिस पर आपका निर्माण किया myTextBoxगया था, इसलिए विंडोज फॉर्म जल्द या बाद में (विशेष रूप से रिलीज़ बिल्ड में) एक अपवाद फेंक देंगे, यह बताते हुए कि आप myTextBoxकिसी अन्य थ्रेड से पहुंच नहीं सकते हैं ।

यही कारण है कि आपको किसी myTextBoxविशेष रूप से असाइनमेंट से पहले श्रमिक थ्रेड से "यूआई थ्रेड" (जहां बनाया गया था) को "स्विच बैक" करना होगा। यह अग्रानुसार होगा:

  1. जब आप अभी भी यूआई थ्रेड पर हैं, तो SynchronizationContextवहां विंडोज फॉर्म पर कब्जा करें , और originalContextबाद में उपयोग के लिए एक चर ( ) में इसका संदर्भ स्टोर करें। आपको SynchronizationContext.Currentइस बिंदु पर क्वेरी करनी चाहिए ; यदि आपने इसे पास किए गए कोड के अंदर क्वेर किया है ThreadPool.QueueUserWorkItem, तो आपको थ्रेड पूल के वर्कर थ्रेड के साथ जो भी सिंक्रोनाइज़ेशन संदर्भ जुड़ा हुआ है वह मिल सकता है। एक बार जब आपने विंडोज फॉर्म के संदर्भ के संदर्भ को संग्रहीत कर लिया है, तो आप इसे यूआई थ्रेड को कोड "भेजने" के लिए कहीं भी और किसी भी समय उपयोग कर सकते हैं।

  2. जब भी आप एक यूआई तत्व में हेरफेर करने की जरूरत है (लेकिन, यूआई धागे पर अब और नहीं कर रहे हैं, या नहीं हो सकता है) के माध्यम से, पहुँच विंडोज फ़ॉर्म 'तुल्यकालन संदर्भ originalContext, और हाथ कोड बंद है कि या तो यूआई हेरफेर होगा Sendया Post


अंतिम टिप्पणी और संकेत:

  • आपके लिए कौन सा सिंक्रनाइज़ेशन संदर्भ नहीं होगा , आपको बता रहा है कि किसी विशिष्ट स्थान / संदर्भ में कौन सा कोड चलना चाहिए, और कौन सा कोड सामान्य रूप से निष्पादित किया जा सकता है, इसे पास किए बिना SynchronizationContext। यह तय करने के लिए, आपको इस मामले में आपके द्वारा प्रोग्रामिंग की जाने वाली रूपरेखा के नियमों और आवश्यकताओं को जानना चाहिए - इस मामले में विंडोज फॉर्म।

    इसलिए विंडोज फॉर्म के लिए इस सरल नियम को याद रखें: जो उन्हें बनाया गया था, उसके अलावा किसी थ्रेड से कंट्रोल या फॉर्म को एक्सेस न करें। यदि आपको ऐसा करना चाहिए, तो SynchronizationContextऊपर वर्णित तंत्र का उपयोग करें , या Control.BeginInvoke(जो कि बिल्कुल वही काम करने का एक विंडोज फॉर्म-विशिष्ट तरीका है)।

  • आप या .NET 4.5 के खिलाफ बाद में कर रहे हैं प्रोग्रामिंग, तो आप अपने कोड है कि स्पष्ट रूप से परिवर्तित करके अपने जीवन को बहुत आसान बना सकते हैं का उपयोग करता है SynchronizationContext, ThreadPool.QueueUserWorkItem, control.BeginInvoke, आदि नए के लिए खत्म हो async/ awaitकीवर्ड और टास्क समानांतर लाइब्रेरी (TPL) , यानी आसपास के एपीआई Taskऔर Task<TResult>वर्गों। ये बहुत हद तक, यूआई थ्रेड के सिंक्रोनाइज़ेशन संदर्भ को कैप्चर करने का ध्यान रखते हैं, अतुल्यकालिक ऑपरेशन शुरू करते हैं, फिर यूआई थ्रेड पर वापस आ रहे हैं ताकि आप ऑपरेशन के परिणाम को संसाधित कर सकें।


आप कहते हैं कि विंडोज फॉर्म, कई अन्य यूआई फ्रेमवर्क की तरह, केवल उसी धागे पर नियंत्रण के हेरफेर की अनुमति देता है लेकिन विंडोज में सभी विंडोज़ को उसी धागे से एक्सेस किया जाना चाहिए जिसने इसे बनाया था।
user34660

4
@ user34660: नहीं, यह सही नहीं है। आपके पास कई थ्रेड हो सकते हैं जो विंडोज फॉर्म कंट्रोल बनाते हैं। लेकिन प्रत्येक नियंत्रण एक धागे से जुड़ा होता है जिसने इसे बनाया है, और इसे केवल उसी एक धागे से एक्सेस किया जाना चाहिए। विभिन्न UI थ्रेड्स से नियंत्रण भी बहुत सीमित हैं कि वे एक-दूसरे के साथ कैसे बातचीत करते हैं: एक दूसरे के माता-पिता / बच्चे नहीं हो सकते हैं, उनके बीच डेटा बंधन संभव नहीं है, आदि अंत में, नियंत्रण बनाने वाले प्रत्येक थ्रेड को अपने संदेश की आवश्यकता होती है लूप (जिसे Application.RunIIRC द्वारा शुरू किया जाता है )। यह एक काफी उन्नत विषय है और लापरवाही से कुछ नहीं किया गया है।
stakx -

मेरी पहली टिप्पणी आपके द्वारा यह कहने के कारण है कि "कई अन्य UI फ्रेमवर्क की तरह" का अर्थ है कि कुछ विंडोज़ एक अलग थ्रेड से "नियंत्रण में हेरफेर" की अनुमति देते हैं लेकिन कोई विंडोज़ विंडोज़ नहीं करता है। आप एक ही विंडो के लिए "कई थ्रेड्स जो विंडोज फॉर्म कंट्रोल बनाते हैं " और "एक ही थ्रेड द्वारा एक्सेस किया जाना चाहिए" और "केवल एक थ्रेड द्वारा एक्सेस किया जाना चाहिए" वही बात कह रहे हैं। मुझे संदेह है कि एक ही विंडो के लिए "विभिन्न UI थ्रेड्स से नियंत्रण" बनाना संभव है। यह सब उन लोगों के लिए उन्नत नहीं है जो पहले .Net पर विंडोज प्रोग्रामिंग के साथ अनुभव करते थे।
user34660

3
यह सब "विंडोज़" और "विंडोज़ विंडोज़" के बारे में बात करता है, बल्कि मुझे चक्कर आ रहा है। क्या मैंने इनमें से किसी भी "विंडोज़" का उल्लेख किया है? मुझे ऐसा नहीं लगता ...
stakx -

1
@ibubi: मुझे यकीन नहीं है कि मैं आपके सवाल को समझ सकता हूँ। किसी भी थ्रेड के सिंक्रनाइज़ेशन संदर्भ को या तो सेट नहीं किया जाता है ( nullया इसका एक उदाहरण SynchronizationContext(या इसका एक उपवर्ग))। उस उद्धरण का बिंदु वह नहीं था जो आपको मिलता है, लेकिन आपको जो नहीं मिलेगा: UI थ्रेड का सिंक्रनाइज़ेशन संदर्भ।
stakx - अब

24

मैं अन्य उत्तरों में जोड़ना चाहूंगा, SynchronizationContext.Postलक्ष्य थ्रेड पर बाद में निष्पादन के लिए एक कॉलबैक (सामान्य रूप से लक्ष्य थ्रेड के संदेश लूप के अगले चक्र के दौरान) को कतार में रखता है, और फिर कॉलिंग थ्रेड पर निष्पादन जारी रहता है। दूसरी ओर, SynchronizationContext.Sendलक्ष्य थ्रेड पर कॉलबैक को तुरंत निष्पादित करने की कोशिश करता है, जो कॉलिंग थ्रेड को ब्लॉक करता है और इसके परिणामस्वरूप गतिरोध हो सकता है। दोनों मामलों में, कोड रीटर्रनेसी के लिए एक संभावना है (निष्पादन के एक ही थ्रेड पर एक क्लास विधि में प्रवेश करने से पहले पिछली कॉल उसी विधि पर वापस आ गई है)।

यदि आप Win32 प्रोग्रामिंग मॉडल से परिचित हैं, तो एक बहुत करीबी सादृश्य होगा PostMessageऔर SendMessageएपीआई, जिसे आप लक्ष्य विंडो के एक से अलग थ्रेड से एक संदेश भेजने के लिए कॉल कर सकते हैं।

यहाँ सिंक्रनाइज़ेशन संदर्भों के बारे में बहुत अच्छी व्याख्या की गई है: यह सभी सिंक्रोनाइज़ेशन कॉन्टेक्स्ट के बारे में है


16

यह सिंक्रोनाइज़ेशन प्रदाता को संग्रहीत करता है, जो सिंक्रोनाइज़ेशन कॉनटेक्स्ट से प्राप्त एक वर्ग है। इस मामले में कि शायद WindowsFormsSynchronizationContext का एक उदाहरण होगा। वह वर्ग Control.Invoke () और Control.BeginInvoke () विधियों को भेजें () और पोस्ट () विधियों को लागू करने के लिए उपयोग करता है। या यह DispatcherSynchronizationContext हो सकता है, यह Dispatcher.Invoke (और BeginInvoke) का उपयोग करता है। Winforms या WPF ऐप में, जैसे ही आप एक विंडो बनाते हैं, वह प्रदाता स्वचालित रूप से इंस्टॉल हो जाता है।

जब आप किसी अन्य थ्रेड पर कोड चलाते हैं, जैसे कि स्निपेट में प्रयुक्त थ्रेड-पूल थ्रेड, तो आपको सावधान रहना होगा कि आप सीधे उन वस्तुओं का उपयोग न करें जो थ्रेड-असुरक्षित हैं। किसी भी यूजर इंटरफेस ऑब्जेक्ट की तरह, आपको TextBox द्वारा बनाए गए थ्रेड से TextBox.Text प्रॉपर्टी को अपडेट करना होगा। पोस्ट () विधि सुनिश्चित करती है कि प्रतिनिधि लक्ष्य उस धागे पर चलता है।

खबरदार कि यह स्निपेट थोड़ा खतरनाक है, यह केवल सही ढंग से काम करेगा जब आप इसे यूआई थ्रेड से कॉल करेंगे। SynchronizationContext.Current के विभिन्न थ्रेड्स में अलग-अलग मान हैं। केवल UI थ्रेड का उपयोग करने योग्य मूल्य है। और यही कारण है कि कोड को इसे कॉपी करना पड़ा। Winforms एप्लिकेशन में इसे करने के लिए एक अधिक पठनीय और सुरक्षित तरीका:

    ThreadPool.QueueUserWorkItem(delegate {
        string text = File.ReadAllText(@"c:\temp\log.txt");
        myTextBox.BeginInvoke(new Action(() => {
            myTextBox.Text = text;
        }));
    });

जिसका यह फायदा है कि यह किसी भी धागे से कॉल करने पर काम करता है । SynchronizationContext.Current का उपयोग करने का लाभ यह है कि यह अभी भी काम करता है कि क्या कोड का उपयोग Winforms या WPF में किया जाता है, यह एक पुस्तकालय में मायने रखता है। यह निश्चित रूप से इस तरह के कोड का एक अच्छा उदाहरण नहीं है, आप हमेशा जानते हैं कि आपके पास किस तरह का टेक्स्टबॉक्स है इसलिए आप हमेशा जानते हैं कि क्या Control.BeginInvoke या Dispatcher.BeginInvoke का उपयोग करना है। वास्तव में SynchronizationContext.Current का उपयोग करना आम नहीं है।

पुस्तक आपको थ्रेडिंग के बारे में सिखाने की कोशिश कर रही है, इसलिए इस त्रुटिपूर्ण उदाहरण का उपयोग करना ठीक है। वास्तविक जीवन में, कुछ मामलों में जहां आप SynchronizationContext.Current का उपयोग करने पर विचार कर सकते हैं , फिर भी आप इसे अपने लिए करने के लिए C # के async / प्रतीक्षा कीवर्ड या TaskScheduler.FromCurrentSynchronizationContext () तक छोड़ देंगे। लेकिन ध्यान दें कि वे अभी भी उसी तरह से दुर्व्यवहार करते हैं जब स्निपेट गलत थ्रेड पर उपयोग करता है, ठीक उसी कारण से। इधर-उधर एक बहुत ही सामान्य प्रश्न, अमूर्तता का अतिरिक्त स्तर उपयोगी है, लेकिन यह पता लगाना कठिन है कि वे सही तरीके से काम क्यों नहीं करते हैं। उम्मीद है कि पुस्तक आपको यह भी बताएगी कि इसका उपयोग कब नहीं करना है :)


मुझे क्षमा करें, क्यों UI थ्रेड हैंडल थ्रेड-सुरक्षित है? यानी मुझे लगता है कि जब पोस्ट () निकाल दिया गया तो UI थ्रेड myTextBox का उपयोग कर सकता है, क्या यह सुरक्षित है?
मेघफैन

4
आपकी अंग्रेजी को डिकोड करना कठिन है। आपका मूल स्निपेट केवल तभी सही ढंग से काम करता है जब इसे यूआई थ्रेड से कहा जाता है। जो बहुत ही सामान्य मामला है। इसके बाद ही यह यूआई थ्रेड पर वापस पोस्ट करेगा। यदि इसे एक श्रमिक थ्रेड से बुलाया जाता है तो पोस्ट () प्रतिनिधि लक्ष्य एक थ्रेडपूल थ्रेड पर चलेगा। Kaboom। यह कुछ ऐसा है जिसे आप अपने लिए आजमाना चाहते हैं। एक थ्रेड प्रारंभ करें और थ्रेड को इस कोड को कॉल करने दें। यदि कोड NullReferenceException के साथ क्रैश होता है, तो आपने इसे सही किया।
हंस पसंत

5

यहाँ सिंक्रनाइज़ेशन संदर्भ का उद्देश्य यह सुनिश्चित करना है कि myTextbox.Text = text;मुख्य UI थ्रेड पर कॉल किया जाता है।

विंडोज के लिए आवश्यक है कि GUI नियंत्रण केवल उस थ्रेड द्वारा एक्सेस किया जाए जिसके साथ वे बनाए गए थे। यदि आप पहले सिंक्रनाइज़ किए बिना पाठ को एक पृष्ठभूमि थ्रेड में असाइन करने का प्रयास करते हैं (किसी भी माध्यम से, जैसे कि यह या इनवोक पैटर्न) तो एक अपवाद फेंक दिया जाएगा।

यह क्या करता है पृष्ठभूमि धागा बनाने से पहले सिंक्रनाइज़ेशन संदर्भ को सहेजता है, फिर पृष्ठभूमि धागा संदर्भ का उपयोग करता है। पोस्ट विधि जीयूआई कोड को निष्पादित करता है।

हां, आपके द्वारा दिखाया गया कोड मूल रूप से बेकार है। पृष्ठभूमि थ्रेड क्यों बनाएं, केवल तुरंत मुख्य UI थ्रेड पर वापस जाने की आवश्यकता है? यह सिर्फ एक उदाहरण है।


4
"हां, आपके द्वारा दिखाया गया कोड मूल रूप से बेकार है। पृष्ठभूमि थ्रेड क्यों बनाएं, केवल तुरंत मुख्य UI थ्रेड पर वापस जाने की आवश्यकता है? यह सिर्फ एक उदाहरण है।" - फ़ाइल से पढ़ना एक लंबा काम हो सकता है यदि फ़ाइल बड़ी है, तो ऐसा कुछ है जो UI थ्रेड को ब्लॉक कर सकता है और इसे अप्रतिसादी बना सकता है
यार नेवेट

मेरे पास एक बेवकूफ सवाल है। प्रत्येक थ्रेड में एक Id होती है, और मुझे लगता है कि UI थ्रेड में एक ID = 2 उदाहरण के लिए है। फिर, जब मैं थ्रेड पूल थ्रेड पर हूं, तो क्या मैं ऐसा कुछ कर सकता हूं: var थ्रेड = GetThread (2); thread.Execute () (> = textbox1.Text = "foo")?
जॉन

@ जॉन - नहीं, मुझे नहीं लगता कि वह काम करता है क्योंकि धागा पहले से ही निष्पादित हो रहा है। आप पहले से ही निष्पादित थ्रेड निष्पादित नहीं कर सकते। निष्पादित केवल तभी काम करता है जब कोई थ्रेड नहीं चल रहा हो (IIRC)
एरिक Funkenbusch

3

स्रोत को

हर सूत्र से जुड़ा एक संदर्भ है - इसे "वर्तमान" संदर्भ के रूप में भी जाना जाता है - और इन संदर्भों को धागे के पार साझा किया जा सकता है। ExecutionContext में वर्तमान परिवेश या संदर्भ का प्रासंगिक मेटाडेटा शामिल है जिसमें कार्यक्रम निष्पादन में है। सिंक्रोनाइज़ेशन कॉन्टेक्स्ट एक अमूर्तता का प्रतिनिधित्व करता है - यह उस स्थान को दर्शाता है जहाँ आपके एप्लिकेशन का कोड निष्पादित होता है।

एक सिंक्रोनाइज़ेशन कॉन्टेक्स्ट आपको किसी अन्य संदर्भ पर किसी कार्य को कतार में खड़ा करने में सक्षम बनाता है। ध्यान दें कि हर धागे का अपना SynchronizatonContext हो सकता है।

उदाहरण के लिए: मान लीजिए कि आपके पास दो धागे हैं, थ्रेड 1 और थ्रेड 2। कहो, थ्रेड 1 कुछ काम कर रहा है, और फिर थ्रेड 1 थ्रेड 2 पर कोड निष्पादित करना चाहता है। इसका एक संभावित तरीका यह है कि थ्रेड 2 को इसके सिंक्रोनाइज़ेशन कॉन्टेक्स्ट ऑब्जेक्ट के लिए कहा जाए, इसे थ्रेड 1 को दिया जाए, और फिर थ्रेड 1 को सिंक्रोनाइज़ेशन कोऑनटेक्स्ट कह सकते हैं। थ्रेड 2 पर कोड निष्पादित करने के लिए भेजें।


2
एक सिंक्रनाइज़ेशन संदर्भ आवश्यक रूप से एक विशेष धागे से बंधा नहीं है। एकाधिक थ्रेड्स के लिए एकल सिंक्रनाइज़ेशन संदर्भ के लिए अनुरोधों को संभालना संभव है, और एकल थ्रेड के लिए कई सिंक्रनाइज़ेशन संदर्भों के लिए अनुरोधों को संभालना संभव है।
सर्व

3

सिंक्रोनाइज़ेशन कॉन्टेक्स्ट हमें एक यूआई को एक अलग थ्रेड से अपडेट करने का एक तरीका प्रदान करता है (सिंक्रोनाइज़ द्वारा सेंड मेथड या एसिंक्रोनसली पोस्ट विधि के माध्यम से)।

निम्नलिखित उदाहरण पर एक नज़र डालें:

    private void SynchronizationContext SyncContext = SynchronizationContext.Current;
    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Thread thread = new Thread(Work1);
        thread.Start(SyncContext);
    }

    private void Work1(object state)
    {
        SynchronizationContext syncContext = state as SynchronizationContext;
        syncContext.Post(UpdateTextBox, syncContext);
    }

    private void UpdateTextBox(object state)
    {
        Thread.Sleep(1000);
        string text = File.ReadAllText(@"c:\temp\log.txt");
        myTextBox.Text = text;
    }

SynchronizationContext.Current यूआई थ्रेड के सिंक संदर्भ को वापस कर देगा। मुझे इसके बारे में कैसे पता है? हर फॉर्म या WPF ऐप के शुरू होने पर, संदर्भ UI थ्रेड पर सेट किया जाएगा। यदि आप एक WPF ऐप बनाते हैं और मेरा उदाहरण चलाते हैं, तो आप देखेंगे कि जब आप बटन पर क्लिक करते हैं, तो यह लगभग 1 सेकंड के लिए सोता है, फिर यह फ़ाइल की सामग्री को दिखाएगा। आप उम्मीद कर सकते हैं क्योंकि यह अपडेटटैक्सबॉक्स विधि (जो कि वर्क 1 है) के कॉलर थ्रेड को पारित करने की एक विधि है, इसलिए यह सोना चाहिए कि मुख्य UI थ्रेड नहीं, एनओपीई! भले ही Work1 विधि एक थ्रेड के लिए पारित की गई है, ध्यान दें कि यह भी एक ऑब्जेक्ट को स्वीकार करता है जो SyncContext है। यदि आप इसे देखते हैं, तो आप देखेंगे कि UpdateTextBox पद्धति को SyncContext.Post विधि के माध्यम से निष्पादित किया गया है न कि Work1 विधि के माध्यम से। निम्नलिखित पर एक नज़र डालें:

private void Button_Click(object sender, RoutedEventArgs e) 
{
    Thread.Sleep(1000);
    string text = File.ReadAllText(@"c:\temp\log.txt");
    myTextBox.Text = text;
}

अंतिम उदाहरण और यह एक ही निष्पादित करता है। यह कार्य करते समय दोनों UI को अवरुद्ध नहीं करता है।

अंत में, एक धागे के रूप में सिंक्रोनाइज़ेशनकोटेक्स्ट के बारे में सोचें। यह एक थ्रेड नहीं है, यह एक थ्रेड को परिभाषित करता है (ध्यान दें कि सभी थ्रेड में सिंककनेक्ट नहीं है)। जब भी हम यूआई को अपडेट करने के लिए उस पर पोस्ट या सेंड मेथड कहते हैं, तो यह मुख्य यूआई थ्रेड से सामान्य रूप से यूआई को अपडेट करने जैसा है। यदि, कुछ कारणों से, आपको UI को एक अलग थ्रेड से अपडेट करने की आवश्यकता है, तो सुनिश्चित करें कि थ्रेड में मुख्य UI थ्रेड का SyncContext है और बस उस पर भेजें या पोस्ट विधि को उस विधि से कॉल करें जिसे आप निष्पादित करना चाहते हैं और आप सभी हैं सेट।

आशा है कि यह आपकी मदद करता है, दोस्त!


2

SynchronizationContext मूल रूप से कॉलबैक प्रतिनिधियों के निष्पादन का एक प्रदाता है, जो मुख्य रूप से यह आश्वासन देने के लिए जिम्मेदार है कि प्रतिनिधियों को किसी प्रोग्राम के कोड के एक विशेष भाग (.net TPL के टास्क ओब्जेक्ट में बाधित) के बाद दिए गए निष्पादन संदर्भ में चलाया जाता है ।

तकनीकी दृष्टिकोण से, SC एक सरल C # वर्ग है जो विशेष रूप से टास्क पैरेलल लाइब्रेरी ऑब्जेक्ट के लिए अपने फ़ंक्शन का समर्थन करने और प्रदान करने के लिए उन्मुख है।

कंसोल अनुप्रयोगों को छोड़कर प्रत्येक .Net अनुप्रयोग, विशिष्ट अंतर्निहित ढांचे के आधार पर इस वर्ग का एक विशेष कार्यान्वयन है, अर्थात: WPF, WindowsForm, Asp Net, Silverlight, ecc ..

इस वस्तु का महत्व कोड के एसिंक्रोनस निष्पादन से वापस आने वाले परिणामों और उस असिंक्रोनस कार्य से परिणाम के लिए प्रतीक्षा कर रहे निर्भर कोड के निष्पादन के बीच सिंक्रोनाइजेशन के लिए बाध्य है।

और शब्द "संदर्भ" निष्पादन के संदर्भ के लिए खड़ा है, जो कि वर्तमान निष्पादन संदर्भ है जहां उस प्रतीक्षा कोड को निष्पादित किया जाएगा, अर्थात सिंक्रनाइज़ेशन बीट्विन एस्किंक कोड और इसका प्रतीक्षा कोड एक विशिष्ट निष्पादन संदर्भ में होता है, इस प्रकार इस वस्तु का नाम सिंक्रोनाइजेशन कॉन्टेक्स्ट है: यह निष्पादन के संदर्भ का प्रतिनिधित्व करता है जो एसिंक्स कोड और वेटिंग कोड निष्पादन के सिंक्रनाइज़ेशन के बाद दिखेगा


1

यह उदाहरण जोसेफ अलबहारी के लिनकैप उदाहरणों से है लेकिन यह वास्तव में यह समझने में मदद करता है कि सिंक्रनाइज़ेशन संदर्भ क्या करता है।

void WaitForTwoSecondsAsync (Action continuation)
{
    continuation.Dump();
    var syncContext = AsyncOperationManager.SynchronizationContext;
    new Timer (_ => syncContext.Post (o => continuation(), _)).Change (2000, -1);
}

void Main()
{
    Util.CreateSynchronizationContext();
    ("Waiting on thread " + Thread.CurrentThread.ManagedThreadId).Dump();
    for (int i = 0; i < 10; i++)
        WaitForTwoSecondsAsync (() => ("Done on thread " + Thread.CurrentThread.ManagedThreadId).Dump());
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.