दिलचस्प पोस्ट
कार्ड विडिओ एंड्रॉइड एल में छाया प्रदर्शित नहीं कर रहा है समूहवार अधिकतम क्वेरी ऑप्टिमाइज़ करें मैक्रो के साथ मेरी Excel कार्यपुस्तिका में मैं सभी धुरी तालिकाओं को कैसे ताज़ा कर सकता हूँ? यौगिक वर्ग के नामों के द्वारा खोज करते समय सुंदर सूप खाली सूची देता है एंड्रॉइड INSTALL_FAILED_UID_CHANGED यूट्यूब एम्बेडेड वीडियो: ऑटोप्ले सुविधा iPhone में काम नहीं कर रहा है यूआरएल से मिलान करने के लिए एक अच्छी नियमित अभिव्यक्ति क्या है? दो रास्ते / उल्टे नक्शा PHP, हेडर के साथ छवि प्रदर्शित करें () क्या एंटाइटीफ़्रेमवर्क 4 को अनुकूलित गुणों को ओवरराइट करने से रोकना संभव है? टेक्स्ट बदलें श्रोता पर एंड्रॉइड गिट में वर्तमान प्रतिबद्धता के लिए हैश कैसे प्राप्त करना है? जावा में HTML को पार्स करने के लिए नियमित अभिव्यक्ति का उपयोग कैसे करें? जावास्क्रिप्ट फ़ंक्शन (क्लाइंट साइड) का निष्पादन रोकें या इसे ट्विक करें एंड्रॉइड Google+ एकीकरण – दोहराया प्रयोक्ता पुनर्प्राप्ति योग्यअनुवाद

क्या मैं डिस्पैच_न्सी_टी को स्टेटिक के बजाय सदस्य चर के रूप में परिभाषित कर सकता हूं?

मैं कोड के एक ब्लॉक केवल प्रति उदाहरण एक बार चलाने के लिए चाहते हैं

क्या मैं डिस्पैच_न्सी_टी की व्याख्या एक स्थैतिक चर के बजाय सदस्य चर के रूप में कर सकता हूं?

जीसीडी संदर्भ से , यह मेरे लिए स्पष्ट नहीं है

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

मुझे पता है कि मैं एक ही बात करने के लिए dispatch_semaphore_t और एक बूलियन झंडा का उपयोग कर सकता हूं। मैं सिर्फ उत्सुक हूँ।

Solutions Collecting From Web of "क्या मैं डिस्पैच_न्सी_टी को स्टेटिक के बजाय सदस्य चर के रूप में परिभाषित कर सकता हूं?"

dispatch_once_t एक उदाहरण चर नहीं होना चाहिए

dispatch_once() कार्यान्वयन के लिए यह आवश्यक है कि dispatch_once_t शून्य है, और कभी भी गैर-शून्य नहीं रहा है पहले-शून्य-शून्य मामले को सही ढंग से काम करने के लिए अतिरिक्त मेमोरी बाधाओं की आवश्यकता होगी, लेकिन dispatch_once() प्रदर्शन के कारणों के लिए उन बाधाओं को छोड़ देता है।

इंस्टेंस चर को शून्य पर आरंभीकृत किया जाता है, लेकिन उनकी स्मृति में पहले से दूसरे मान को संग्रहीत किया हो सकता है। यह उन्हें डिस्पैच_ऑन्सी dispatch_once() उपयोग के लिए असुरक्षित बनाता है

16 नवंबर को अपडेट करें

मूल रूप से इस प्रश्न को 2012 में "मनोरंजन" के साथ उत्तर दिया गया था, उसने एक निश्चित जवाब प्रदान करने का दावा नहीं किया और उस प्रभाव को चेतावनी दी। अंत में ऐसे मनोरंजन को निजी तौर पर रहना चाहिए, हालांकि कुछ लोगों ने इसका आनंद उठाया था।

अगस्त 2016 में यह क्यू एंड ए मेरे ध्यान में लाया गया था और मैंने एक उचित जवाब दिया। उसमें लिखा है:

मैं ग्रेग पार्कर से प्रतीत होता है कि असहमत हूं, लेकिन शायद वास्तव में नहीं …

ठीक है, ऐसा लगता है कि ग्रेग और मैं इससे असहमत हूं कि क्या हम असहमत हैं, या उत्तर, या कुछ और 😉 इसलिए मैं अपने उत्तर में 2016 के उत्तर को अद्यतन करने के लिए अधिक विस्तृत आधार के साथ अपडेट कर रहा हूं, यह गलत क्यों हो सकता है और यदि ऐसा है तो इसे ठीक करने के लिए (इसलिए मूल प्रश्न का उत्तर अभी भी "हां" है)। उम्मीद है कि ग्रेग और मैं या तो सहमत होंगे, या मैं कुछ सीखूंगा – या तो परिणाम अच्छा है!

तो पहले 16 अगस्त को जवाब दिया गया था, तो जवाब के आधार के लिए एक स्पष्टीकरण दिया गया था। किसी भी भ्रम से बचने के लिए मूल मनोरंजन को हटा दिया गया है, इतिहास के छात्र संपादन पथ को देख सकते हैं।


उत्तर: अगस्त 2016

मैं ग्रेग पार्कर से प्रतीत होता है कि असहमत हूं, लेकिन शायद वास्तव में नहीं …

मूल प्रश्न:

क्या मैं डिस्पैच_न्सी_टी की व्याख्या एक स्थैतिक चर के बजाय सदस्य चर के रूप में कर सकता हूं?

लघु उत्तर: उत्तर हां दिया गया है वस्तु की प्रारंभिक रचना और dispatch_once किसी भी उपयोग के बीच मेमोरी बाधा है।

त्वरित विवरण: प्रेषण_एन्सीएसी के लिए dispatch_once_t चर पर आवश्यकता यह है कि यह शुरू में शून्य होना चाहिए। आधुनिक मल्टीप्रोसेसरों पर मेमोरी री-ऑर्डरिंग ऑपरेशन से मुश्किल आती है। हालांकि यह प्रदर्शित हो सकता है कि किसी स्थान के लिए एक स्टोर कार्यक्रम पाठ (उच्च स्तरीय भाषा या कोडांतरक स्तर) के अनुसार किया गया है, वास्तविक स्टोर को फिर से क्रमबद्ध किया जा सकता है और उसी स्थान के बाद के पढ़ने के बाद हो सकता है। इस मेमोरी बाधाओं का समाधान करने के लिए इस्तेमाल किया जा सकता है जो सभी स्मृति कार्यों को उनसे अनुसरण करने से पहले पूरा करने के लिए बाध्य करता है। ऐसा करने के लिए एप्पल OSMemoryBarrier() प्रदान करता है

dispatch_once साथ एप्पल यह बता रहा है कि शून्य-प्रारंभिक वैश्विक चर शून्य होने की गारंटी है, लेकिन शून्य-प्रारंभिक आवृत्ति चर (और शून्य प्रारंभिक उद्देश्य-सी डिफ़ॉल्ट यहां है) किसी भी dispatch_once निष्पादित होने से पहले शून्य होने की गारंटी नहीं है।

समाधान एक स्मृति बाधा डालने के लिए है; इस धारणा पर कि प्रेषण_एक उदाहरण के कुछ सदस्य विधि में यह स्मृति बाधा डाल करने के लिए एक स्पष्ट स्थान (1) के रूप में init पद्धति में है, यह केवल एक बार निष्पादित होगा (उदाहरण के तौर पर) और (2) init पहले लौटा होगा किसी अन्य सदस्य विधि को कहा जा सकता है।

तो हां, एक उपयुक्त मेमोरी बाधा के साथ, dispatch_once को एक आवृत्ति चर के साथ प्रयोग किया जा सकता है


नवम्बर 2016

प्रस्तावना: प्रेषण_ऑन्स पर नोट्स

ये नोट एप्पल के कोड पर आधारित हैं और dispatch_once लिए टिप्पणियां हैं।

डिस्पैच_ऑन्स का उपयोग मानक पैटर्न का अनुसरण करता है:

 id cachedValue; dispatch_once_t predicate = 0; ... dispatch_once(&predicate, ^{ cachedValue = expensiveComputation(); }); ... use cachedValue ... 

और पिछले दो पंक्तियों को इनलाइन ( dispatch_once एक मैक्रो है) की तरह विस्तारित किया गया है:

 if (predicate != ~0) // (all 1's, indicates the block has been executed) [A] { dispatch_once_internal(&predicate, block); // [B] } ... use cachedValue ... // [C] 

टिप्पणियाँ:

  • ऐप्पल के सूत्र में कहा गया है कि predicate शून्य पर आरंभ किया जाना चाहिए और यह नोट करता है कि ग्लोबल और स्टैटिक वैरिएबल डिफॉल्ट से शून्य आरंभिकता के लिए।

  • ध्यान दें कि पंक्ति [ए] में कोई स्मृति बाधा नहीं है सट्टेबाज़ी पढ़ने-आगे और शाखा cachedValue साथ एक प्रोसेसर पर लाइन में cachedValue का cachedValue [सी] पंक्ति [ए] में predicate होने से पहले हो सकता है, जिससे गलत परिणाम हो सकता है ( cachedValue वैल्यू के लिए गलत मान)

  • इसे रोकने के लिए एक बाधा का इस्तेमाल किया जा सकता है, हालांकि यह धीमा है और एप्पल इसे सामान्य मामले में तेजी से रखना चाहता है कि एक बार ब्लॉक पहले से ही किया जा चुका है, इसलिए …

  • dispatch_once_internal , लाइन [बी], जो आंतरिक रूप से बाधाओं और परमाणु संचालन का उपयोग करता है, एक विशेष बाधा का प्रयोग करता है, dispatch_atomic_maximally_synchronizing_barrier() सट्टा पढ़ा-आगे को हराने के लिए और इसलिए लाइन [ए] को बाधा रहित और इसलिए तेज़ होने की अनुमति देता है।

  • कोई भी प्रोसेसर तक पहुंचने वाली पंक्ति [ए] dispatch_once_internal() को निष्पादित करने और predicate जरूरतों को उत्परिवर्तित करने से पहले, ग्लोबल या स्थैतिक का प्रयोग करके predicate शून्य के लिए यह गारंटी देगा।

हमारे मौजूदा प्रयोजनों के लिए महत्वपूर्ण दूर लेना यह है कि प्रेषण_अभिव्यक्त उत्परिवर्तित इस तरह से predicate करता है कि लाइन [ए] बिना किसी बाधा के काम करती है

16 अगस्त की लंबी व्याख्या:

इसलिए हम शून्य से आरंभिक वैश्विक या स्थैतिक का उपयोग करते हैं, जो डिस्पैच_ऑन्सी dispatch_once() के अवरोध रहित फास्टपाथ की आवश्यकताओं को पूरा करती है। हम यह भी जानते हैं कि डिस्पैच_न्सी_इनरीन dispatch_once_internal() द्वारा किए गए उत्परिवर्तन सही ढंग से संभाले जाते हैं

हमें यह निर्धारित करने की आवश्यकता है कि क्या हम एक उदाहरण चर का उपयोग predicate लिए कर सकते हैं और इसे इस तरह शुरू कर सकते हैं कि ऊपर की पंक्ति [ए] ऊपर कभी-कभी इसका प्रारंभिक मूल्य नहीं पढ़ सकता है – जैसे कि चीजें टूट सकती हैं

मेरे 16 अगस्त उत्तर का कहना है कि यह संभव है। इसके लिए आधार को समझने के लिए हमें एक बहु-प्रोसेसर के वातावरण में प्रोग्राम और डेटा प्रवाह पर विचार करने की ज़रूरत है, जो सट्टा आधारित पढ़ने-आगे है।

16 अगस्त के उत्तर के निष्पादन और डेटा प्रवाह की रूपरेखा है:

 Processor 1 Processor 2 0. Call alloc 1. Zero instance var used for predicate 2. Return object ref from alloc 3. Call init passing object ref 4. Perform barrier 5. Return object ref from init 6. Store or send object ref somewhere ... 7. Obtain object ref 8. Call instance method passing obj ref 9. In called instance method dispatch_once tests predicate, This read is dependent on passed obj ref. 

उदाहरण के रूप में एक उदाहरण चर का उपयोग करने में सक्षम होने के लिए चरण 9 को इस तरह से निष्पादित करना असंभव होना चाहिए कि वह चरण 1 से पहले उसे स्मृति में मान पढ़ता है।

यदि चरण 4 को छोड़ा गया है, तो कोई भी उपयुक्त बाधा init में डाली जाती है, हालांकि प्रोसेसर 2 को चरण 9 निष्पादित करने से पहले प्रोसेसर 1 द्वारा उत्पन्न ऑब्जेक्ट संदर्भ के लिए सही मान प्राप्त करना होगा, यह संभव है (सैद्धांतिक रूप से) संभव है कि प्रोसेसर 1 का शून्य स्टेप 1 में लिखते हैं कि अभी तक वैश्विक मेमोरी और प्रोसेसर 2 के लिए कोई प्रदर्शन / लिखा नहीं किया गया है, उन्हें नहीं दिखाई देगा।

इसलिए हम चरण 4 को सम्मिलित करते हैं और एक बाधा करते हैं।

हालांकि अब हमें सट्टा पढ़ना-आगे विचार करना होगा, जैसे कि dispatch_once() को करना है चरण 4 की बाधा से पहले प्रोसेसर 2 चरण 9 की पढ़ाई कर सकता है क्या यह सुनिश्चित किया गया है कि स्मृति शून्य है?

विचार करें:

  • प्रोसेसर 2, अनुमानित रूप से या अन्यथा, चरण 9 की पढ़ाई नहीं कर सकता, जब तक कि चरण 7 में प्राप्त ऑब्जेक्ट संदर्भ नहीं है – और ऐसा करने के लिए प्रोसेसर को यह निर्धारित करने की आवश्यकता होती है कि चरण 8 में विधि कॉल, जिसका लक्ष्य उद्देश्य-सी में है गतिशील रूप से निर्धारित, चरण 9 वाले विधि पर समाप्त होगा, जो काफी उन्नत है (लेकिन असंभव नहीं) सट्टा;

  • चरण 6 ऑब्जेक्ट संदर्भ को चरण 6 तक संग्रहीत / पास नहीं कर सकता;

  • चरण 6 को इसे स्टोर / पास करने के लिए नहीं मिला, जब तक कि चरण 5 ने इसे वापस नहीं किया है; तथा

  • चरण 5 चरण 4 पर बाधा के बाद है …

टीएल; डीआर : चरण 9 में अवरोध वाले चरण 4 के बाद तक पढ़ने के लिए आवश्यक ऑब्जेक्ट संदर्भ कैसे हो सकता है? (और कई शाखाओं के साथ, लंबे समय तक निष्पादन मार्ग दिया गया, कुछ सशर्त (जैसे विधि प्रेषण के अंदर), सट्टा सट्टा पढ़ा-आगे एक मुद्दा है?)

तो मैं तर्क देता हूं कि चरण 4 में बाधा पर्याप्त है, यहां तक ​​कि सट्टा के आगे पढ़ने-आगे के चरण 9 की उपस्थिति में भी।

ग्रेग की टिप्पणियों पर विचार:

ग्रेग ने एप्लेट की स्रोत कोड की टिप्पणी को "शून्य पर आरंभ किया जाना" से "वास्तविक रूप से शून्य होना चाहिए" के बारे में टिप्पणी को मजबूत किया है, जिसका मतलब लोड लोड होने के बाद से है, और यह केवल वैश्विक और स्थिर चर के लिए सही है, यह तर्क बाधा रहित dispatch_once() फास्ट पथ के लिए आवश्यक आधुनिक प्रोसेसर द्वारा सट्टा सट्टा पढ़ने को आगे बढ़ाने पर आधारित है।

उदाहरण चर ऑब्जेक्ट निर्माण समय पर शून्य करने के लिए शुरू किए जाते हैं, और जो स्मृति में वे कब्जा कर लेते हैं, उसके बाद से शून्य हो सकता था। हालांकि जैसा कि एक उपयुक्त बाधा से ऊपर तर्क दिया गया है, यह सुनिश्चित करने के लिए इस्तेमाल किया जा सकता है कि dispatch_once() पूर्व-प्रारंभिक मूल्य को नहीं पढ़ता है। मुझे लगता है कि ग्रेग मेरी बहस के साथ असहमत है, अगर मैं अपनी टिप्पणियों का सही ढंग से पालन करता हूं, और तर्क देता है कि चरण 4 में बाधा अप्रत्याशित पठन-आगे को संभालने के लिए अपर्याप्त है।

मान लीजिए ग्रेग सही है (जो बिल्कुल असंभव नहीं है!), तो हम एक स्थिति में हैं, जो एप्पल पहले ही प्रेषण_ऑनसीस dispatch_once() , हमें पढ़ने-आगे को हराने की जरूरत है एप्पल ऐसा करता है कि dispatch_atomic_maximally_synchronizing_barrier() बाधा का उपयोग करके हम चरण 4 में इस तरह की बाधा का इस्तेमाल कर सकते हैं और निम्नलिखित कोड को निष्पादित करने से रोकते हैं, जब तक कि संभवतया सट्टा-प्रोसेसर 2 द्वारा आगे पढ़ा न जाए; और निम्न कोड के रूप में, चरण 5 और 6, प्रोसेसर 2 के पास निष्पादित होना चाहिए, यहां तक ​​कि एक ऑब्जेक्ट संदर्भ भी है जो यह अनुमान लगाया जा सकता है कि स्टेप 9 सब कुछ काम करता है।

इसलिए यदि मैं ग्रेग की चिंताओं को समझता हूं तो फिर dispatch_atomic_maximally_synchronizing_barrier() का उपयोग करके उन्हें संबोधित किया जाएगा, और एक मानक बाधा के बजाय इसका उपयोग करने से कोई समस्या नहीं होगी, भले ही यह वास्तव में आवश्यक न हो। हालांकि मुझे विश्वास नहीं है कि यह आवश्यक है कि यह ऐसा करने के लिए बेहद खराब है। मेरा निष्कर्ष इसलिए पहले जैसा है (जोर दिया गया है):

तो हां, एक उपयुक्त मेमोरी बाधा के साथ, dispatch_once को एक आवृत्ति चर के साथ प्रयोग किया जा सकता है

मुझे यकीन है कि ग्रेग या कुछ अन्य पाठक मुझे बताएंगे कि क्या मैंने अपने तर्क में चूक की है मैं खड़े होने के लिए तैयार हूं!

निश्चित रूप से आपको यह तय करना होगा कि init में उचित बाधा की कीमत एक बार प्रति उदाहरण वाले व्यवहार को प्राप्त करने के लिए dispatch_once() का उपयोग करने से लाभ के लायक है या आप अपनी आवश्यकताओं को एक और तरीके से संबोधित करना चाहिए या नहीं – और ऐसे विकल्पों के बाहर हैं इस जवाब का दायरा!

dispatch_atomic_maximally_synchronizing_barrier() लिए कोड:

dispatch_atomic_maximally_synchronizing_barrier() की परिभाषा, जिसे एप्पल के स्रोत से लिया गया है, जिसका उपयोग आप अपने कोड में कर सकते हैं:

 #if defined(__x86_64__) || defined(__i386__) #define dispatch_atomic_maximally_synchronizing_barrier() \ ({ unsigned long _clbr; __asm__ __volatile__( "cpuid" : "=a" (_clbr) : "0" (0) : "ebx", "ecx", "edx", "cc", "memory"); }) #else #define dispatch_atomic_maximally_synchronizing_barrier() \ ({ __c11_atomic_thread_fence(dispatch_atomic_memory_order_seq_cst); }) #endif 

यदि आप जानना चाहते हैं कि यह कैसे ऐप्पल के स्रोत कोड को पढ़ता है

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