2012-06-25 51 views
2

我正在使用GCD的dispatch_after方法當我的應用程序正在加載執行某些行爲。預期的行爲是從applicationDidFinishLaunchingWithOptions的末尾等待3秒鐘以執行在後臺隊列中運行的選擇器。GCD dispatch_after調用導致SIGBUS信號

我的測試設備上沒有遇到任何崩潰,但我遇到了未捕獲的SIGBUS信號的用戶崩潰報告,原因是BUS_ADRALN異常。根據我對此代碼的理解,BUS_ADRALN錯誤表示地址對齊錯誤。

這是我如何創建我的定時器:

double delayInSeconds = 3.0; 
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 
dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), 
        ^(void){ 
         [self methodToPerformInBackground]; 
        }); 

什麼導致這個崩潰?

由於多線程錯誤可能是一種奇怪的怪物,我會拋出一些我一直在腦海中徘徊的想法。

  • 我打來電話給[self performSelectorOnMainThread:withObject:waitUntilDone]。在這種稱爲選擇器的選擇器中執行此操作有什麼問題嗎?
  • 由於我打電話dispatch_get_global_queue而不是dispatch_create_queue,我不需要保留此方法返回的隊列。這個推理是否正確?
  • 在此代碼中,self是應用程序委託。嘗試在應用程序進入後臺或終止後執行該塊會導致崩潰嗎?應用程序在關閉時是否自動清理所有調度的塊?
  • 被調用方法內部的東西導致崩潰,但GCD不提供堆棧跟蹤。

編輯:我寧願不包括被稱爲該塊中的代碼,因爲我不相信這是最主要的問題,反正。這是堆棧跟蹤。線程0上的崩潰使得它好像是GCD中的問題,而不是塊中調用的代碼。

編輯#2:通過更多的崩潰報告後,我有奇怪的消息分享。這個崩潰只出現在運行iOS 4.2.X及更低版本的用戶上。由於GCD支持iOS 4.0及更高版本,我的猜測是4.3中有一個錯誤修正。

Thread 0 Crashed: 
0 libSystem.B.dylib     0x35e5fb10 _dispatch_retain + 0 
1 libSystem.B.dylib     0x35e5df8c dispatch_after_f + 80 
2 libSystem.B.dylib     0x35e5e070 dispatch_after + 72 
3 MyApplication        0x0000466c -[MyApplicationDelegate applicationDidFinishLaunchingPart2:] (MyApplicationDelegate.m:366) 
4 CoreFoundation      0x37538f79 -[NSObject(NSObject) performSelector:withObject:] + 25 
5 Foundation       0x35171e6d __NSThreadPerformPerform + 273 
6 CoreFoundation      0x375518d1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15 
7 CoreFoundation      0x37521ecd __CFRunLoopDoSources0 + 385 
8 CoreFoundation      0x375216f9 __CFRunLoopRun + 265 
9 CoreFoundation      0x3752150b CFRunLoopRunSpecific + 227 
10 CoreFoundation      0x37521419 CFRunLoopRunInMode + 61 
11 GraphicsServices     0x33e76d24 GSEventRunModal + 196 
12 UIKit        0x3591d57c -[UIApplication _run] + 588 
13 UIKit        0x3591a558 UIApplicationMain + 972 
14 MyApplication        0x00003024 main (main.m:113) 

Thread 1: 
0 libSystem.B.dylib     0x35d8f974 kevent + 24 
1 libSystem.B.dylib     0x35e5dd70 _dispatch_queue_invoke + 104 
2 libSystem.B.dylib     0x35e5d790 _dispatch_worker_thread2 + 128 
3 libSystem.B.dylib     0x35de6978 _pthread_wqthread + 400 

Thread 2: 
0 libSystem.B.dylib     0x35de72fc __workq_kernreturn + 8 

Thread 3: 
0 libSystem.B.dylib     0x35d5b3b0 mach_msg_trap + 20 
1 CoreFoundation      0x37521f83 __CFRunLoopServiceMachPort + 95 
2 CoreFoundation      0x37521787 __CFRunLoopRun + 407 
3 CoreFoundation      0x3752150b CFRunLoopRunSpecific + 227 
4 CoreFoundation      0x37521419 CFRunLoopRunInMode + 61 
5 WebCore       0x3318bd1c _ZL12RunWebThreadPv + 532 
6 libSystem.B.dylib     0x35de5b4c _pthread_start + 372 

Thread 4: 
0 libSystem.B.dylib     0x35d5b3b0 mach_msg_trap + 20 
1 CoreFoundation      0x37521f83 __CFRunLoopServiceMachPort + 95 
2 CoreFoundation      0x37521787 __CFRunLoopRun + 407 
3 CoreFoundation      0x3752150b CFRunLoopRunSpecific + 227 
4 CoreFoundation      0x37521419 CFRunLoopRunInMode + 61 
5 Foundation       0x3517ec55 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 217 
6 Foundation       0x3515cb91 -[NSThread main] + 49 
7 Foundation       0x35155b97 __NSThread__main__ + 915 
8 libSystem.B.dylib     0x35de5b4c _pthread_start + 372 
+0

如果您聲稱發生了崩潰,需要查看該方法中的代碼。否則,我們應該怎麼做? – borrrden

+0

@borrrden,該方法中有太多的代碼需要共享。該方法正在執行一些文件IO並讀取原子(但不是線程安全的)屬性值。我雖然添加了堆棧跟蹤。如果這沒有幫助,我會添加一些代碼。 – goldierox

+0

你是否靜態分析過你的代碼?在3秒的發送之前您是否在屏幕上顯示任何內容? – Nico

回答

1

DISPATCH_QUEUE_PRIORITY_BACKGROUND是iOS 5.0+特性。如果您嘗試在iOS 4.x上使用它,它將爲NULL(當您嘗試保留它時會崩潰,因爲GCD是一個C庫,並且在目標中使用nil的方式使用NULL並不安全-C)。有關更多信息,請參閱this answer。解決方案是使用低優先級,或使用預處理器指令在兩者之間切換。

+0

感謝@borrrden。你是完全正確的。我不能相信我在文檔中錯過了這一點。剛剛看到它下面的「iOS 4.0及更高版本」。 DISPATCH_QUEUE_PRIORITY_BACKGROUND在iOS 4上正常工作。3設備,即使文檔說只有5.0+支持它。 – goldierox

+0

我敢打賭,他們在iOS 4.3中私下推出了它,然後一旦它被測試使它在5.0中公開。蘋果經常做這樣的事情。 – borrrden

+0

您可能想澄清爲什麼它保留時會崩潰。通常,發送'nil''retain'消息是安全的。它不是在這種情況下,因爲編譯器使用C函數'dispatch_retain'來代替。 (只是說,「當你試圖用'dispatch_retain'來保留它時,我會認爲這是澄清的。) –

相關問題