26

मैं अपने ऐप में प्रमाणीकरण विधि का परीक्षण करने के लिए किवी परीक्षण ढांचे का उपयोग कर रहा हूं। एक फोन पर परीक्षण फ्रीज़ dispatch_sync को जो इस तरह दिखता है:यह dispatch_sync() कॉल फ्रीज क्यों है?

dispatch_queue_t main = dispatch_get_main_queue(); 
dispatch_sync(main,^
        { 
         [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret]; 
        }); 

मुझे पता है कि वह वहाँ क्यों जम जाता है, अगर कोई किसी भी संकेत है चाहते हैं।

+0

क्योंकि आप मुख्य कतार पर एक ब्लॉक enqueuing रहे हैं यह deadlocking है - जो मुख्य थ्रेड पर है - और उस के लिए प्रतीक्षा करने के लिए मुख्य थ्रेड कह पूरा करने के लिए ब्लॉक। –

+0

चूंकि आपने जो जवाब स्वीकार कर लिया है, वह उस कार्य को संबोधित नहीं करता है जिस पर आपने पूछा था, मैंने उस भाग को प्रश्न से हटा दिया है। डेडलॉकिंग प्रश्न का पहले से ही कई बार जवाब दिया गया है (और दस्तावेज़ों में भी है): http://stackoverflow.com/questions/7816159/dispatch-sync-on-main-queue-hangs-in-unit-test, http : //stackoverflow.com/questions/10315645/app-blocks-while-dipatching-a-queue, http://stackoverflow.com/questions/10984732/gcd-why-cant-we-use-a-dispatch-sync -ऑन-द-वर्तमान-कतार, लेकिन मैंने सोचा कि एक जीसीडी समारोह को रोकने के बारे में सवाल काफी दिलचस्प था। –

+0

धन्यवाद।अगर मुझे पता था कि यह एक डेडलॉक मुद्दा था, तो मैं सवाल को सही तरीके से तैयार कर सकता था या Google को खोजकर समाधान ढूंढ सकता था। यह जानना अच्छा होगा कि dispatch_sync को कैसे दबाया जाए, लेकिन हो सकता है कि यह उचित समाधान न हो। – teubanks

उत्तर

50

फ्रीज पर संकेत के बारे में अपने प्रश्न के दूसरे भाग के लिए:

जब एक कतार पर dispatch_sync बुला, हमेशा सत्यापित करें कि इस कतार में पहले से ही वर्तमान कतार (dispatch_get_current_queue()) नहीं है। क्योंकि dispatch_sync आपके पैरामीटर को पहले पैरामीटर के रूप में पारित कतार पर कतारबद्ध करेगा, और फिर जारी रखने से पहले इस ब्लॉक को निष्पादित करने की प्रतीक्षा करेगा।

तो यदि dispatch_get_current_queue() और जिस कतार पर आप अपने ब्लॉक को एनक्यू करते हैं, वही है, अर्थात् आपके मामले में मुख्य कतार है, मुख्य कतार प्रेषण_एसआईएनसी को कॉल पर अवरुद्ध कर देगी ... मुख्य कतार ब्लॉक को निष्पादित करने के रूप में, लेकिन ऐसा नहीं हो सकता है, क्योंकि कतार अवरुद्ध है, और आपके पास पर एक सुंदर डेडलॉक है।

एक समाधान ([संपादित करें] ऊपर iOS6 तक):

dispatch_queue_t main = dispatch_get_main_queue(); 
dispatch_block_t block =^
       { 
        [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationAuthenticationSuccess object:nil userInfo:ret]; 
       }; 
if (dispatch_get_current_queue() == main) 
    block(); // execute the block directly, as main is already the current active queue 
else 
    dispatch_sync(main, block); // ask the main queue, which is not the current queue, to execute the block, and wait for it to be executed before continuing 

[संपादित करें] सावधान रहें, dispatch_get_current_queue() केवल है डीबगिंग उद्देश्यों के लिए और उत्पादन में कभी नहीं इस्तेमाल किया जाएगा। वास्तव में, dispatch_get_current_queue आईओएस 6.1.3 के बाद से हटा दिया गया है।

यदि आप मुख्य कतार (जो केवल मुख्य धागे से जुड़े हैं) के विशिष्ट मामले में हैं, तो आप इसके बजाय @ अर्थ-मामलों द्वारा सुझाए गए अनुसार [NSThread isMainThread] का परीक्षण कर सकते हैं।


वैसे, क्या आप वाकई अपने मामले में dispatch_sync करने की जरूरत है? मुझे लगता है कि थोड़ी देर बाद आपकी अधिसूचना भेजना, इसे भेजने तक ब्लॉक करने से परहेज करना आपके मामले में स्वीकार्य है, इसलिए आप dispatch_async (dispatch_sync का उपयोग करने और कतार तुलना की स्थिति की आवश्यकता के बजाय) का उपयोग करने पर भी विचार कर सकते हैं, जो डेडलॉक से बचें मुद्दा भी

+0

यह एक शानदार जवाब है। Dispatch_sync का उपयोग करने का कारण यह है क्योंकि इसे dispatch_async कॉल के भीतर बुलाया जा रहा है (सुनिश्चित नहीं है कि यह समझ में आता है)। एक और तरीका रखो, यह एक तुल्यकालिक प्रक्रिया का एक हिस्सा है जो एक एसिंक्रोनस थ्रेड के भीतर होता है। – teubanks

+1

ध्यान रखें कि यदि आप एक साझा संसाधन तक पहुंच को क्रमबद्ध करने के लिए प्रेषण कतारों का उपयोग कर रहे हैं, तो ब्लॉक को निष्पादित करने से तुरंत सूक्ष्म बग का कारण बन सकता है क्योंकि dispatch_sync ब्लॉक को उसी कतार को लक्षित करने वाले dispatch_async ब्लॉक से पहले निष्पादित किया जाएगा, भले ही एसिंक ब्लॉक पहले जमा किया गया था। –

+1

यह समाधान आईओएस 6.1.3 पर/से काम नहीं करता है ([नीचे मेरा जवाब देखें] (http://stackoverflow.com/a/15692778/1971013))। और 'dispatch_get_current_queue()' बहिष्कृत है। –

36

dispatch_get_current_queue() आईओएस 6, और dispatch_get_current_queue() == dispatch_get_main_queue() से शुरू होने से बहिष्कृत किया गया है जबकि आईओएस 6.1.3 पर मुख्य धागे पर false पाया गया था।

iOS 6 में और बस से बाहर कार्य करें:

dispatch_block_t block =^
{ 
    <your code here> 
}; 

if ([NSThread isMainThread]) 
{ 
    block(); 
} 
else 
{ 
    dispatch_sync(dispatch_get_main_queue(), block); 
} 
+1

भयानक के बारे में चेतावनी के लिए – vikas

+2

अभी भी आईओएस 8.2 पर काम कर रहा है। – Naeem

+0

@ अर्थ-मामलों का समर्थन आपके लिए धन्यवाद ;-) – Naeem

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