2012-06-25 3 views
2

일부 동작을 수행하기 위해 응용 프로그램을로드 할 때 GCD의 dispatch_after 메서드를 사용하고 있습니다. 의도 된 동작은 백그라운드 대기열에서 실행되는 선택기를 수행하기 위해 applicationDidFinishLaunchingWithOptions 끝에서 3 초를 기다리는 것입니다.SIGBUS 신호를 발생시키는 GCD dispatch_after 호출

테스트 장치에서 충돌이 발생하지는 않았지만 잡히지 않은 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를 수행하고 원자 적 (thread-safe는 아님) 속성 값을 읽는 것입니다. 스택 추적을 추가했습니다. 이것이 도움이되지 않는다면 몇 가지 코드를 추가하겠습니다. – goldierox

+0

코드를 정적으로 분석 했습니까? 3 초 파견 전에 화면에 무엇인가 선물을하고 있습니까? @borrrden 감사합니다. – Nico

답변

1

DISPATCH_QUEUE_PRIORITY_BACKGROUND는 iOS 5.0 이상 기능입니다. iOS 4.x에서 사용하려고하면 NULL이됩니다 (GCD는 C 라이브러리이므로 NULL을 사용하는 것이 안전하지 않으므로 충돌을 시도하면 충돌이 발생합니다). 목표는 nil입니다. -기음). 자세한 내용은 this answer을 참조하십시오. 해결책은 대신 낮은 우선 순위를 사용하거나 전 처리기 지시문을 사용하여 둘 사이를 전환하는 것입니다.

+0

. 너는 완전히 옳다. 나는 그 문서에서 그것을 놓쳤다는 것을 믿을 수 없다. 그 아래에있는 "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"으로 유지하려고 할 때 이것을 분명히 할 것입니다.) –