2009-02-16 9 views
15

मेरे iPhone ग्राहक अतुल्यकालिक अनुरोध के साथ भागीदारी का एक बहुत है, बहुत समय लगातार शब्दकोशों या सरणियों के स्थिर संग्रह संशोधित। नतीजतन, यह आम है मुझे बड़ा डेटा संरचनाओं जो अधिक समय लग निम्न त्रुटियों के साथ एक सर्वर से पुनः प्राप्त करने के लिए देखने के लिए:अतुल्यकालिक यूआरएल के साथ mutexes के iPhone उपयोग का अनुरोध करता है

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <NSCFArray: 0x3777c0> was mutated while being enumerated.' 

आमतौर पर इसका अर्थ यह है कि सर्वर के दो अनुरोध डेटा जो कोशिश कर रहे हैं के साथ वापस आ एक ही संग्रह को संशोधित करें। जो मैं खोज रहा हूं वह इस हानिकारक त्रुटि से बचने के लिए मेरे कोड को व्यवस्थित तरीके से कैसे व्यवस्थित करने का एक ट्यूटोरियल/उदाहरण/समझ है। मुझे विश्वास है कि सही जवाब म्यूटेक्स है, लेकिन मैंने कभी भी व्यक्तिगत रूप से उनका उपयोग नहीं किया है।

यह NSURLConnection के साथ अतुल्यकालिक HTTP अनुरोध बनाने और उसके बाद प्रतिनिधिमंडल के एक साधन के रूप NSNotification सेंटर की मदद से एक बार अनुरोध पूरा कर रहे हैं का परिणाम है। जब अनुरोधों को फायरिंग करते हैं जो समान संग्रह सेट को म्यूट करते हैं, तो हमें इन टकराव मिलते हैं।

उत्तर

15

तो यह संभव है कि (वर्ग सहित) किसी भी डेटा दो धागे से पहुँचा जा जाएगा एक साथ आप इन सिंक्रनाइज़ रखने के लिए कदम उठाने चाहिए।

सौभाग्य से ऑब्जेक्टिव-सी यह हास्यास्पद आसान इस सिंक्रनाइज़ कीवर्ड का उपयोग करने के लिए बनाता है। यह कीवर्ड किसी ऑब्जेक्टिव-सी ऑब्जेक्ट को तर्क के रूप में लेता है। सिंक्रनाइज़ किए गए सेक्शन में एक ही ऑब्जेक्ट निर्दिष्ट करने वाले किसी अन्य थ्रेड को पहले खत्म होने तक रोक दिया जाएगा।

-(void) doSomethingWith:(NSArray*)someArray 
{  
    // the synchronized keyword prevents two threads ever using the same variable 
    @synchronized(someArray) 
    { 
     // modify array 
    } 
} 

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

// Get the semaphore. 
id groupSemaphore = [Group semaphore]; 

@synchronized(groupSemaphore) 
{ 
    // Critical group code. 
} 
28

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

@synchronized(sStaticData) { 
    // Do something with sStaticData 
} 

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

NSLock *lock = [[NSLock alloc] init]; 
// ... later ... 
[lock lock]; 
// Do something with shared data 
[lock unlock]; 
// Much later 
[lock release], lock = nil; 

आप इनमें से किसी उपाय लेने का फैसला करते यह दोनों रीड और राईट के लिए आप NSMutableArray/सेट का उपयोग कर रहे के बाद से ताला प्राप्त करने के लिए जरूरी होगा/जो कुछ भी एक डेटा स्टोर के रूप में। जैसा कि आपने देखा है NSFastEnumeration ऑब्जेक्ट के उत्परिवर्तन के उत्परिवर्तन को प्रतिबंधित करता है।

लेकिन मुझे लगता है यहाँ एक और मुद्दा एक बहु थ्रेडेड वातावरण में डेटा संरचनाओं की पसंद है। क्या यह कई धागे से आपके शब्दकोश/सरणी तक पहुंचने के लिए कड़ाई से जरूरी है? या पृष्ठभूमि धागे उन्हें प्राप्त डेटा को जोड़ सकते हैं और फिर इसे मुख्य थ्रेड पर पास कर सकते हैं जो डेटा तक पहुंचने के लिए एकमात्र थ्रेड होगा?

+0

समस्या यह है कि 'पृष्ठभूमि' धागे स्पष्ट रूप से मेरे द्वारा बनाए गए नहीं हैं। वे एसिंक्रोनस NSURLConnection अनुरोधों का परिणाम हैं। मेरे पास कोड के माध्यम से मुख्य धागे से बात करने का कोई तरीका नहीं है। आपके अन्य सुझाव उपयोगी हैं हालांकि मैं इसकी सराहना करता हूं। – Coocoo4Cocoa

+0

मेरा मानना ​​है कि NSURLConnection के प्रतिनिधि को थ्रेड पर कॉल किया जाएगा जिसने लोड ऑपरेशन शुरू किया था, जरूरी नहीं कि थ्रेड जिसने ऑब्जेक्ट बनाया था। तो आप अपने प्रतिनिधि तरीकों में डेटा को जोड़ सकते हैं। – sbooth

+0

हां! धन्यवाद यह मेरे लिए काम करता है। – Armanoide

0

sStaticData और NSLock जवाब के जवाब में (टिप्पणी 600 वर्ण तक सीमित हैं), तो आप (एक धागा सुरक्षित तरीका में sStaticData और NSLock वस्तुओं बनाने से बचने के लिए के बारे में बहुत सावधान रहना होगा की जरूरत नहीं है विभिन्न धागे द्वारा बनाए जा रहे कई ताले के बहुत ही असंभव परिदृश्य)?

मुझे लगता है कि दो तरीके दिए देखते हैं:

1) आप उन वस्तुओं एक मूल सूत्र में दिन की शुरुआत में बनाया करने के जनादेश कर सकते हैं।

2) एक स्थैतिक वस्तु को परिभाषित करें जो स्वचालित रूप से लॉक के रूप में उपयोग करने के लिए दिन की शुरुआत में बनाया गया है, उदा।

static NSString *sMyLock1 = @"Lock1"; 

तो मुझे लगता है कि आप सुरक्षित रूप से

@synchronized(sMyLock1) 
{ 
    // Stuff 
} 

उपयोग कर सकते हैं अन्यथा मैं अपने ताले बनाने के साथ लगता है कि आप हमेशा एक 'चिकन और अंडे' की स्थिति में पहुंच जाएंगे: एक स्थिर NSString इनलाइन बनाया जा सकता है एक थ्रेड सुरक्षित तरीके से?

बेशक, आप इनमें से किसी भी समस्या को हिट करने की संभावना नहीं रखते हैं क्योंकि अधिकांश आईफोन ऐप्स एक ही थ्रेड में चलते हैं।

मुझे पहले [समूह सेमफोर] सुझाव के बारे में पता नहीं है, यह भी एक समाधान हो सकता है।

+0

"पिछला जवाब"? अभी दो अन्य उत्तर हैं। –

+0

मैंने अब इसे स्पष्ट करने के लिए अद्यतन किया है (एफटीआर, मेरा मतलब है कि इस से ऊपर का जवाब दिया गया है - मैंने एसटीटीएटीडीएटी और एनएसएलॉक का जिक्र किया है, वहां बहुत अस्पष्टता नहीं है)! –

0

एनबी। "। एक्सेप्शन हैंडलिंग"

ऑब्जेक्टिव-सी प्रदान करता है धागा तुल्यकालन और अपवाद हैंडलिंग, जो इस लेख और से वर्णन किया गया के लिए समर्थन: आप तुल्यकालन उपयोग कर रहे हैं अपने जीसीसी झंडे को -fobjc-exceptions जोड़ने के लिए भूल नहीं है इन सुविधाओं के लिए समर्थन चालू करें, जीएनयू कंपाइलर संग्रह (जीसीसी) संस्करण 3.3 और बाद में -fobjc-अपवाद स्विच का उपयोग करें।

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/ObjectiveC/Articles/ocThreading.html

0

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

NSMutableArray *originalArray = @[@"A", @"B", @"C"]; 
NSMutableArray *arrayToEnumerate = [originalArray copy]; 

अब arrayToEnumerate को संशोधित करें। चूंकि इसे मूल आरे के संदर्भ में नहीं दिया गया है, लेकिन मूल ऐरे की एक प्रति है, इससे कोई समस्या नहीं आएगी।

0

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

dispatch_async(serial_queue, ^{ 
    <#critical code#> 
}) 

डाल मामले में यदि आप जब तक काम पूरा, आप आम तौर पर

dispatch_sync(serial_queue Or concurrent, ^{ 
    <#critical code#> 
}) 

उपयोग कर सकते हैं निष्पादन के लिए इंतजार नहीं, अतुल्यकालिक करने का एक पसंदीदा तरीका है की जरूरत है doest वर्तमान निष्पादन इंतजार करना चाहते हैं।

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