C # ईवेंट समकालिक हैं?


104

इस प्रश्न के दो भाग हैं:

  1. करता है की परवरिश एक घटना धागा ब्लॉक, या यह EventHandlers के निष्पादन एसिंक्रोनस रूप से शुरू होता है और धागा चला जाता है एक ही समय में पर जारी है?

  2. क्या व्यक्तिगत ईवेंटहैंडलर (ईवेंट के लिए सब्सक्राइब किए गए) एक के बाद एक समान रूप से चलते हैं, या क्या वे अतुल्यकालिक रूप से बिना किसी गारंटी के चलते हैं कि अन्य एक ही समय में नहीं चल रहे हैं?

जवाबों:


37

अपने सवालों के जवाब देने के लिए:

  1. यदि कोई घटना ईवेंट हैंडलर सभी सिंक्रनाइज़ किए गए हैं, तो किसी घटना को उठाना थ्रेड को ब्लॉक करता है।
  2. घटना संचालकों को क्रमिक रूप से निष्पादित किया जाता है, एक के बाद एक, क्रम में उन्हें घटना के लिए सदस्यता दी जाती है।

मैं भी आंतरिक तंत्र eventऔर इसके संबंधित संचालन के बारे में उत्सुक था । इसलिए मैंने एक साधारण कार्यक्रम लिखा और ildasmइसके कार्यान्वयन के बारे में सोचता था।

संक्षिप्त उत्तर है

  • घटनाओं की सदस्यता लेने या इनवॉइस करने में कोई अतुल्यकालिक ऑपरेशन शामिल नहीं है।
  • घटना उसी प्रतिनिधि प्रकार के एक बैकिंग प्रतिनिधि क्षेत्र के साथ कार्यान्वित की जाती है
  • सदस्यता के साथ किया जाता है Delegate.Combine()
  • सदस्यता समाप्त किया गया है Delegate.Remove()
  • केवल संयुक्त संयुक्त प्रतिनिधि को आमंत्रित करके किया जाता है

यहाँ मैंने क्या किया है। मैंने जो कार्यक्रम उपयोग किया है:

public class Foo
{
    // cool, it can return a value! which value it returns if there're multiple 
    // subscribers? answer (by trying): the last subscriber.
    public event Func<int, string> OnCall;
    private int val = 1;

    public void Do()
    {
        if (OnCall != null) 
        {
            var res = OnCall(val++);
            Console.WriteLine($"publisher got back a {res}");
        }
    }
}

public class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo();

        foo.OnCall += i =>
        {
            Console.WriteLine($"sub2: I've got a {i}");
            return "sub2";
        };

        foo.OnCall += i =>
        {
            Console.WriteLine($"sub1: I've got a {i}");
            return "sub1";
        };

        foo.Do();
        foo.Do();
    }
}

यहाँ फू का कार्यान्वयन है:

यहां छवि विवरण दर्ज करें

ध्यान दें कि एक क्षेत्र OnCall और एक घटना है OnCall । क्षेत्र OnCallस्पष्ट रूप से समर्थन करने वाली संपत्ति है। और यह महज एक हैFunc<int, string> , यहाँ कुछ भी नहीं फैंसी।

अब दिलचस्प भाग हैं:

  • add_OnCall(Func<int, string>)
  • remove_OnCall(Func<int, string>)
  • और कैसे OnCallइनवॉइस किया जाता हैDo()

सब्स्क्राइब्ड और अनसब्सक्राइब इम्प्लीमेंट कैसे किया जाता है?

यहाँ add_OnCallCIL में संक्षिप्त कार्यान्वयन है। दिलचस्प हिस्सा यह है कि यह Delegate.Combineदो प्रतिनिधियों को सम्‍मिलित करने के लिए उपयोग करता है।

.method public hidebysig specialname instance void 
        add_OnCall(class [mscorlib]System.Func`2<int32,string> 'value') cil managed
{
  // ...
  .locals init (class [mscorlib]System.Func`2<int32,string> V_0,
           class [mscorlib]System.Func`2<int32,string> V_1,
           class [mscorlib]System.Func`2<int32,string> V_2)
  IL_0000:  ldarg.0
  IL_0001:  ldfld      class [mscorlib]System.Func`2<int32,string> ConsoleApp1.Foo::OnCall
  // ...
  IL_000b:  call       class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
                                                                                          class [mscorlib]System.Delegate)
  // ...
} // end of method Foo::add_OnCall

इसी तरह, Delegate.Removeमें प्रयोग किया जाता हैremove_OnCall

किसी घटना को कैसे लागू किया जाता है?

आह्वान करने के लिए OnCallमें Do(), यह बस आर्ग लोड करने के बाद अंतिम श्रेणीबद्ध प्रतिनिधि कॉल:

IL_0026:  callvirt   instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)

किसी ग्राहक को किसी घटना की सदस्यता कैसे मिलती है?

और अंत में, में Main, आश्चर्य की बात नहीं, उदाहरण के लिए OnCallकॉलिंग add_OnCallविधि द्वारा घटना की सदस्यता ली जाती है Foo


3
बहुत बढ़िया!! जब से मैंने यह प्रश्न पूछा है, यह बहुत लंबा है। यदि आप शीर्ष पर वर्बेज लगा सकते हैं जो सीधे मेरे दो भाग प्रश्न का उत्तर देता है (जैसे, "# 1 उत्तर नहीं है; # 2 उत्तर नहीं है") तो मैं इसे आधिकारिक उत्तर दूंगा। मैं आपके पोस्ट को अपने मूल प्रश्नों के उत्तर देने के लिए सभी टुकड़ों के रूप में शर्त लगा रहा हूं, लेकिन चूंकि मैं C # का उपयोग नहीं करता हूं (और अन्य googlers इन अवधारणाओं के लिए नए हो सकते हैं) इसलिए मैं वर्बेज के लिए पूछ रहा हूं जो उत्तरों को स्पष्ट करता है।
अलेक्जेंडर बर्ड

धन्यवाद @AlexanderBird, शीर्ष पर जवाब डालने के लिए बस इसे संपादित किया।
KFL

@ केएफएल, यह अभी भी स्पष्ट नहीं है, मैं एलेक्स के रूप में एक ही टिप्पणी छोड़ने वाला था। एक सरल "हाँ, वे सिंक्रोनस हैं", सहायक होगा
जॉनी 5

71

यह एक सामान्य उत्तर है और डिफ़ॉल्ट व्यवहार को दर्शाता है:

  1. हां, यह थ्रेड को ब्लॉक करता है, अगर इवेंट में सदस्यता लेने वाले तरीके एसिंक्रोनस नहीं हैं।
  2. उन्हें एक के बाद एक अंजाम दिया जाता है। इसका एक और मोड़ है: यदि कोई ईवेंट हैंडलर अपवाद छोड़ता है, तो ईवेंट हैंडलर को अभी तक निष्पादित नहीं किया जाएगा।

यह कहते हुए कि, हर वर्ग जो घटनाओं को प्रदान करता है, वह अपने कार्यक्रम को अतुल्यकालिक रूप से लागू करने का विकल्प चुन सकता है। IDesign नामक एक वर्ग प्रदान करता है जो इसे EventsHelperसरल बनाता है

[नोट] इस लिंक के लिए आपको EventHelper वर्ग डाउनलोड करने के लिए एक ई-मेल पता प्रदान करना होगा। (मैं किसी भी तरह से संबद्ध नहीं हूं)


मैंने कुछ फोरम पोस्ट पढ़े हैं, जिनमें से दो ने पहले बिंदु का खंडन किया है, जबकि एक उचित कारण प्रदान नहीं किया है। मुझे आपके उत्तर पर संदेह नहीं है, (यह मेरे अब तक के अनुभव से मेल खाता है) क्या पहले बिंदु पर कोई आधिकारिक दस्तावेज है? मुझे इसके बारे में निश्चित होने की आवश्यकता है, लेकिन मुझे इस सटीक मामले पर कुछ भी आधिकारिक खोजने में कठिनाइयां हैं।
एडम एलएस

@ AdamL.S। यह कैसे घटना कहा जाता है की बात है। तो यह वास्तव में घटना प्रदान करने वाले वर्ग पर निर्भर करता है।
डैनियल हिल्गारथ

14

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

चूंकि घटनाओं को मल्टीकास्ट प्रतिनिधियों के साथ परिभाषित किया जाता है, आप अपने स्वयं के फायरिंग तंत्र का उपयोग करके लिख सकते हैं

Delegate.GetInvocationList();

और प्रतिनिधियों को अतुल्यकालिक रूप से आमंत्रित करना;


12

इवेंट्स केवल प्रतिनिधियों के सरणियाँ हैं। जब तक प्रतिनिधि कॉल सिंक्रोनस है, तब तक ईवेंट भी सिंक्रोनस हैं।


7

सामान्य तौर पर, ईवेंट समकालिक होते हैं। हालांकि, कुछ अपवाद हैं, जैसे कि System.Timers.Timer.Elapsedघटना ThreadPoolअगर SyncronisingObjectशून्य पर एक धागे पर उठाई जा रही है।

डॉक्स: http://msdn.microsoft.com/en-us/library/system.timers.timer.elaps.nx


3

जब तक आप मैन्युअल रूप से एक दूसरा धागा शुरू नहीं करते हैं, तब तक C # में इवेंट सिंक्रोनाइज़ (दोनों मामलों में) चलाएं।


क्या मैं एक async घटना हैंडलर का उपयोग करें? क्या यह फिर दूसरे धागे में चलेगा? मैंने "Async all the way" के बारे में सुना है, लेकिन ऐसा लगता है जैसे async इवेंट हैंडलर्स का अपना एक धागा होता है? मुझे समझ में नहीं आता: / क्या आप मुझे बता सकते हैं?
विंगर सेंटन

3

घटनाएँ समकालिक हैं। यही कारण है कि ईवेंट जीवनचक्र उस तरह से काम करता है जैसे कि करता है। भार लोड करने से पहले होता है, भार रेंडर से पहले होता है आदि।

यदि किसी हैंडलर को किसी घटना के लिए निर्दिष्ट नहीं किया जाता है, तो चक्र केवल धुंधला हो जाता है। यदि एक से अधिक हैंडलर निर्दिष्ट किए गए हैं, तो उन्हें क्रम में बुलाया जाएगा और एक तब तक जारी नहीं रह सकता जब तक कि दूसरा पूरी तरह से समाप्त न हो जाए।

यहां तक ​​कि अतुल्यकालिक कॉल एक डिग्री के लिए तुल्यकालिक हैं। शुरुआत पूरी होने से पहले अंत को कॉल करना असंभव होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.