ऑब्जेक्टिव-सी में @synchronized लॉक / अनलॉक कैसे होता है?


201

क्या पारस्परिक बहिष्कार को प्राप्त करने के लिए @synchronized ने "लॉक" और "अनलॉक" का उपयोग नहीं किया है? फिर यह लॉक / अनलॉक कैसे करता है?

निम्नलिखित कार्यक्रम का आउटपुट केवल "हैलो वर्ल्ड" है।

@interface MyLock: NSLock<NSLocking>
@end

@implementation MyLock

- (id)init {
    return [super init];
}

- (void)lock {
    NSLog(@"before lock");
    [super lock];
    NSLog(@"after lock");
}

- (void)unlock {
    NSLog(@"before unlock");
    [super unlock];
    NSLog(@"after unlock");
}

@end


int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    MyLock *lock = [[MyLock new] autorelease];
    @synchronized(lock) {
        NSLog(@"Hello World");
    }

    [pool drain];
}


10
यदि आपको इसकी आवश्यकता नहीं है, तो आपको init को ओवरराइड करने की आवश्यकता नहीं है। यदि आप किसी विधि को ओवरराइड नहीं करते हैं तो रनटाइम स्वचालित रूप से सुपरक्लास के कार्यान्वयन को कॉल करता है।
कांस्टेंटिनो त्सरोहास

3
एक महत्वपूर्ण बात यह है कि उपरोक्त कोड सिंक्रनाइज़ नहीं है। lockवस्तु हर कॉल पर बनाई गई है, इसलिए वहाँ एक मामला कभी नहीं होगा, जहां एक @synchronizedदूसरे को ब्लॉक ताले। और इसका मतलब है कि कोई पारस्परिक बहिष्करण नहीं है।) बेशक, उपरोक्त उदाहरण ऑपरेशन कर रहा है main, इसलिए वैसे भी बाहर करने के लिए कुछ भी नहीं है, लेकिन किसी को उस कोड को नेत्रहीन रूप से कॉपी नहीं करना चाहिए।
हॉट लाइक्स

3
इस SO पृष्ठ को पढ़ने के बाद, मैंने @synchronized की जांच करने का निर्णय लिया और थोड़ा और अच्छी तरह से इस पर एक ब्लॉग पोस्ट लिखा। आपको यह उपयोगी लग सकता है: rykap.com/objective-c/2015/05/09/synchronized
rjkaplan

जवाबों:


323

ऑब्जेक्टिव-सी लैंग्वेज लेवल सिंक्रोनाइजेशन म्यूटेक्स का उपयोग करता है, ठीक उसी तरह जैसे NSLock। शब्दार्थ में कुछ छोटे तकनीकी अंतर हैं, लेकिन मूल रूप से उनके बारे में सोचना सही है क्योंकि एक सामान्य (अधिक आदिम) इकाई के शीर्ष पर लागू दो अलग-अलग इंटरफेस।

विशेष रूप से NSLockआपके पास एक स्पष्ट लॉक होता है, जबकि @synchronizedआपके पास एक अंतर्निहित लॉक होता है जो उस वस्तु से जुड़ा होता है जिसे आप सिंक्रनाइज़ करने के लिए उपयोग कर रहे हैं। भाषा के स्तर के लॉकिंग का लाभ संकलक को समझ में आता है इसलिए यह स्कूपिंग के मुद्दों से निपट सकता है, लेकिन यंत्रवत् वे मूल रूप से एक ही व्यवहार करते हैं।

आप @synchronizedएक संकलक के रूप में सोच सकते हैं :

- (NSString *)myString {
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

में बदल जाता है:

- (NSString *)myString {
  NSString *retval = nil;
  pthread_mutex_t *self_mutex = LOOK_UP_MUTEX(self);
  pthread_mutex_lock(self_mutex);
  retval = [[myString retain] autorelease];
  pthread_mutex_unlock(self_mutex);
  return retval;
}

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


17
आप उस अपवाद हैंडलिंग को भी भूल रहे हैं जो @synchronized आपके लिए करता है। और जैसा कि मैं इसे समझता हूं, इसमें से अधिकांश को रनटाइम पर नियंत्रित किया जाता है। यह अनियंत्रित ताले पर अनुकूलन की अनुमति देता है, आदि
क्विन टेलर

7
जैसा कि मैंने कहा, वास्तविक उत्पन्न सामान अधिक जटिल है, लेकिन DWAR3 खोलना तालिकाओं के निर्माण में अनुभाग निर्देशों को लिखने में मेरा मन नहीं लगा ;-)
लुई

और मैं तुम्हें दोष नहीं दे सकता। :-) यह भी ध्यान दें कि OS X DWARF के बजाय Mach-O प्रारूप का उपयोग करता है।
क्विन टेलर

5
द्विआधारी प्रारूप के रूप में DWARF का उपयोग कोई नहीं करता है। OS X डिबग प्रतीकों के लिए DWARF का उपयोग करता है, और यह शून्य लागत अपवादों के लिए DWARF खोल तालिकाओं का उपयोग करता है
लुई गेरबार

7
संदर्भ के लिए, मैंने मैक ओएस एक्स ;-) के लिए संकलक बैकएंड लिखा है;
लुई गेरबार

40

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

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


1
वह लिंक समाप्त हो गया है। यहां अपडेट की गई लिंक है: developer.apple.com/library/archive/documentation/Cocoa/…
एरियल स्टेनर

31

वास्तव में

{
  @synchronized(self) {
    return [[myString retain] autorelease];
  }
}

में सीधे रूपांतरित करता है:

// needs #import <objc/objc-sync.h>
{
  objc_sync_enter(self)
    id retVal = [[myString retain] autorelease];
  objc_sync_exit(self);
  return retVal;
}

यह एपीआई iOS 2.0 के बाद से उपलब्ध है और इसका उपयोग करके आयात किया गया है ...

#import <objc/objc-sync.h>

तो यह साफ तौर पर फेंके गए अपवादों को संभालने के लिए कोई समर्थन नहीं देता है?
डस्टिन

क्या यह कहीं दस्तावेज है?
jbat100

6
वहाँ एक असंतुलित ब्रेस है।
पोटाटोस्वाटर

@ डस्टिन वास्तव में डॉक्स से करता है: "एहतियाती उपाय के रूप में, @synchronizedब्लॉक अनुमानित रूप से संरक्षित कोड में एक अपवाद हैंडलर जोड़ता है। यह हैंडलर स्वचालित रूप से उस घटना में म्यूटेक्स को रिलीज़ करता है जो एक अपवाद फेंक दिया गया है।"
पीटर

objc_sync_enter शायद pthread म्यूटेक्स का उपयोग करेगा, इसलिए लुई का रूपांतरण गहरा और सही है।
जैक

3

Apple के @synchronized का कार्यान्वयन खुला स्रोत है और इसे यहाँ पाया जा सकता है । माइक ऐश ने इस विषय पर दो दिलचस्प पोस्ट लिखी हैं:

संक्षेप में, इसमें एक तालिका होती है जो ऑब्जेक्ट पॉइंटर्स (उनके मेमोरी एड्रेस को कुंजियों के रूप में उपयोग करते हुए) को pthread_mutex_tलॉक करती है, जिन्हें लॉक किया जाता है और आवश्यकतानुसार अनलॉक किया जाता है।


-4

यह सिर्फ हर वस्तु के साथ एक सेमाफोर को जोड़ता है, और इसका उपयोग करता है।


तकनीकी रूप से, यह म्यूटेक्स लॉक बनाता है, लेकिन मूल विचार सही है। Apple दिवा को यहां देखें: developer.apple.com/documentation/Cocoa/Conceptual/…
मार्क बेसे

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