2009-07-31 9 views
183

क्या @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]; 
} 
+0

नोट: http://stackoverflow.com/questions/1215765/ –

+10

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

+1

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

उत्तर

296

उद्देश्य-सी भाषा स्तर सिंक्रनाइज़ेशन mutex का उपयोग करता है, जैसे 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

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

+5

जैसा कि मैंने कहा था, वास्तविक जेनरेट की गई सामग्री अधिक जटिल है, लेकिन मुझे डीडब्ल्यूएआरएफ 3 टेबल को खोलने के क्रम में अनुभाग निर्देश लिखना पसंद नहीं आया ;-) –

+0

और मैं दोष नहीं दे सकता आप। :-) यह भी ध्यान दें कि ओएस एक्स डीडब्ल्यूएआरएफ के बजाय मैक-ओ प्रारूप का उपयोग करता है। –

-2

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

+0

तकनीकी रूप से, यह एक म्यूटेक्स लॉक बनाता है, लेकिन मूल विचार सही है। ऐप्पल डिवा को यहां देखें: http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW16 –

+3

न केवल एक म्यूटेक्स, लेकिन एक रिकर्सिव लॉक। – kperryua

37

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

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

29

असल

{ 
    @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; 
} 

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

#import <objc/objc-sync.h> 
+0

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

+0

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

+6

वहाँ एक असंतुलित ब्रेस है। – Potatoswatter

1

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

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

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