2013-09-04 9 views
10

ब्लॉक के भीतर dispatch_async() को कॉल करते समय @synchronized() का उपयोग करते हुए आईओएस में लॉक का क्या होता है।सिंक्रनाइज़ किए गए ब्लॉक और dispatch_async

पूर्व के लिए:

id myID 
-(void) foobar 
{ 
    @synchronized(myID){ 
     dispatch_async(){ //do stuff with myID}; 
    } 
} 

ताला अभी भी dispatch_async कॉल के भीतर वैध है? या अधिक महत्वपूर्ण बात यह है कि dispatch_async() के अंदर किसी अन्य @ सिंक्रनाइज़() कॉल का उपयोग करने में कोई कमी है?

+0

आप क्या हासिल करने की कोशिश कर रहे हैं? – Wain

+0

बीटीडब्लू, क्या मैं यह मानने में सही हूं कि आप किसी भी समय 'myID' को पुनर्स्थापित नहीं कर रहे हैं? '@ सिंक्रनाइज़ किया गया 'ब्लॉक' myID' द्वारा इंगित ऑब्जेक्ट के उस विशेष उदाहरण के लिए अद्वितीय है, सामान्य रूप से चर नहीं। – Rob

उत्तर

3

लॉक केवल एक ही समय में दो अलग-अलग ब्लॉक भेजे जाने से रोक देगा। हालांकि वे असीमित रूप से प्रेषित किए जाते हैं, इसलिए उन्हें तब तक निष्पादित किया जा सकता है या भविष्य में मनमाने ढंग से किया जा सकता है। प्रेषण कॉल भी उनके पूरा होने की प्रतीक्षा नहीं करेगा।

तो ब्लॉक के अंदर की सामग्री सिंक्रनाइज़ नहीं है। यह प्राप्त करने के विकल्प कि न्यूनतम परिवर्तनों के साथ एक सिंक्रोनस प्रेषण या ब्लॉक के भीतर बस सिंक्रनाइज़ करना है।

आप जो कर रहे हैं उसके आधार पर, एक सीरियल प्रेषण कतार स्थापित करने और अपने ब्लॉक को उस पर प्रेषित करने का सबसे अच्छा विचार हो सकता है।

8

मान लें कि आप पृष्ठभूमि कतार में इस myID ऑब्जेक्ट के साथ बातचीत को सिंक्रनाइज़ करने का प्रयास कर रहे हैं, तो आप इसे प्रेषित ब्लॉक के अंदर लॉक के आसपास दूसरी तरफ चाहते हैं। अभी आपके पास:

@synchronized(myID) { 
    dispatch_async(queue, ^{ 
     // do stuff with myID 
    }); 
} 

अपने कतार में भेजा ब्लॉक जोड़ने की प्रक्रिया को सिंक्रनाइज़ है कि है, लेकिन करता है नहीं सिंक्रनाइज़ क्या आप पृष्ठभूमि में कर रहे हैं। मुझे संदेह है कि आपका मतलब क्या नहीं है।

आप शायद इरादा:

dispatch_async(queue, ^{ 
    @synchronized(myID) { 
     // do stuff with myID 
    } 
}); 

यह बहुत समान दिखता है, लेकिन एक पूरी तरह से अलग व्यवहार में परिणाम है। अब, पृष्ठभूमि कतार में भेजा गया कार्य सिंक्रनाइज़ किया जा रहा है।

एक और शोधन के रूप में, अगर यह भेजा ब्लॉक संभवतः धीमी है (और मैं यह हो सकता है ग्रहण), तो आप शायद जितना संभव हो उतना @synchronized ब्लॉक विवश करना चाहते हैं:

dispatch_async(queue, ^{ 

    // do slow stuff in preparation for interacting with `myID` 

    @synchronized(myID) { 
     // quickly do stuff with myID 
    } 

    // do anything else here 
}); 

आप तो @synchronized ब्लॉक के भीतर सभी पृष्ठभूमि ब्लॉक करें, आप पृष्ठभूमि को प्रेषित करने के लिए पूरे उद्देश्य को हरा सकते हैं, अर्थात् मुख्य कतार पर प्रभाव को कम करने के लिए। यह अंतिम प्रतिपादन उस समस्या को कम करता है।

अंतिम अवलोकन के रूप में, यदि आपके पास एक धारावाहिक कतार है (या एक गैर-वैश्विक समवर्ती कतार जिसमें आप बाधा के साथ अपडेट करते हैं), जिसे अक्सर ऐसी तकनीक के रूप में उपयोग किया जाता है जो ताले की पूरी तरह से आवश्यकता को समाप्त करता है, जब तक myID के लिए सभी अपडेट और पूछताछ उस कतार में प्रेषित की जाती हैं। Concurrency प्रोग्रामिंग गाइड में Eliminating Lock-Based Code देखें।

+0

जब आप कहते हैं "मुख्य कतार पर प्रभाव कम करें" तो आपका मतलब केवल पृष्ठभूमि प्रक्रिया में अधिक समय लगेगा, है ना? काम अभी भी पृष्ठभूमि कतार में किया जा रहा है और उदाहरण नहीं होगा यूआई ब्लॉक करें। – Ixx

+0

@Ixx - नहीं, मेरा मुद्दा यह है कि यदि (ए) आप बैकग्राउंड थ्रेड पर 'सिंक्रनाइज़' ब्लॉक के अंदर कुछ समय लेने वाले होते हैं; और (बी) यदि मुख्य धागे को 'myID' तक पहुंचने की भी आवश्यकता है (और इसलिए भी' @ सिंक्रनाइज़ 'का उपयोग करना होगा), तो आपकी पृष्ठभूमि' सिंक्रनाइज़ 'ब्लॉक आसानी से मुख्य धागे को अवरुद्ध कर सकती है, जिससे इसे प्रेषित करने के उद्देश्य को हराया जा सकता है। एक पृष्ठभूमि कतार पूरी तरह से सामान। इसलिए, जब पृष्ठभूमि थ्रेड को '@ सिंक्रनाइज़' करना होता है, तो सुनिश्चित करें कि आप जितनी जल्दी हो सके अंदर और बाहर आते हैं, '@ सिंक्रनाइज़ किए गए' ब्लॉक के बाहर समय लेने वाली सामग्री को रखते हुए, यदि आप कर सकते हैं। – Rob

संबंधित मुद्दे