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

它鎖死,因爲你在排隊的主隊列塊 - 這是在主線程中 - 並告訴主線程等待塊完成。 –

+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在當前隊列中,但我認爲關於存儲GCD函數的問題非常有趣。 –

+0

謝謝。如果我知道這是一個僵局問題,我可以適當地調整問題的範圍,或者通過搜索谷歌找到解決方案。知道如何存根dispatch_sync仍然很好,但也許這不是一個合適的解決方案。 – teubanks

回答

50

對於你的問題就關於凍結的提示第二部分:

當調用上的隊列dispatch_sync總是驗證此隊列尚未當前隊列dispatch_get_current_queue())。因爲dispatch_sync會將您的塊排列在作爲第一個參數傳遞的隊列上,然後將等待此塊被執行,然後繼續

所以如果dispatch_get_current_queue()和你排隊你的塊的隊列是相同的,也就是你的情況下的主隊列,主隊列將阻塞對dispatch_sync的調用,直到......主隊列執行塊,但是它不能,因爲隊列被阻塞,所以你在這裏有一個美麗的死鎖

一個解決方案([編輯],直到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自iOS6.1.3開始已被棄用。

如果您處於主隊列(僅與主線程相關聯)的特定情況,您可以按照@意義事件的建議測試[NSThread isMainThread]


順便說一句,你確定你需要dispatch_sync你的情況嗎? 我想稍後發送你的通知,避免阻塞,直到它被髮送,在你的情況下是可以接受的,所以你也可以考慮使用dispatch_async(而不是使用dispatch_sync並需要隊列比較條件),這將避免死鎖也是問題。

+0

這是一個夢幻般的答案。我們使用dispatch_sync的原因是因爲它在dispatch_async調用中被調用(不確定這是否合理)。換句話說,它是異步線程內發生的同步過程的一部分。 – teubanks

+1

請記住,如果您使用分派隊列來串行訪問共享資源,則立即執行該塊有時會導致細微的錯誤,因爲dispatch_sync塊將在dispatch_async塊針對同一隊列之前執行,即使異步塊首先提交。 –

+1

此解決方案不適用於iOS 6.1.3([請參閱我的答案](http://stackoverflow.com/a/15692778/1971013))。 'dispatch_get_current_queue()'已棄用。 –

36

dispatch_get_current_queue()已從iOS 6開始棄用,並且在iOS 6.1.3的主線程上發現dispatch_get_current_queue() == dispatch_get_main_queue()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

仍在iOS 8.2上工作。 – Naeem

+0

@意義事項感謝您的支持;-) – Naeem