2016-12-08 4 views
2

So zur Zeit meine App kann in einem Zustand landen, wo eine Netzwerkanfrage gemacht wird, und eine andere der gleichen Anfrage kann, während die erste Anforderung noch gemacht werden, ist für die AntwortWas tun `_dispatch_barrier_sync_f_invoke` und` _dispatch_barrier_sync_f_slow`?

Wenigstens denke ich warten. Und mit dieser Logik, es sieht aus wie Gewinde 11 zuerst dreht, und dann Gewinde 13. Dann 13 sieht Faden wie es wartet, weil Faden 11 immer noch auf eine Antwort wartet

Gewinde 11 hat: _dispatch_barrier_sync_f_invoke und Gewinde 13 hat: _dispatch_barrier_sync_f_slow

Thread 11 Crashed: 
0 libsystem_kernel.dylib    0x00007fffab4d1dda __pthread_kill + 10 
1 libsystem_c.dylib     0x00007fffab437440 abort + 129 
2 CrashReporter      0x000000010f28d851 uncaught_exception_handler (PLCrashReporter.m:365) 
3 CoreFoundation      0x00007fff963d7e29 __handleUncaughtException + 745 
4 libobjc.A.dylib      0x00007fffaaac9b85 _ZL15_objc_terminatev + 94 
5 libc++abi.dylib      0x00007fffa9fbdd69 _ZSt11__terminatePFvvE + 8 
6 libc++abi.dylib      0x00007fffa9fbdde3 _ZSt9terminatev + 51 
7 libobjc.A.dylib      0x00007fffaaac998e objc_terminate + 9 
8 libdispatch.dylib     0x00007fffab36d13c _dispatch_client_callout + 28 
9 libdispatch.dylib    --->0x00007fffab36dd62 _dispatch_barrier_sync_f_invoke + 83 
10 Snagit        0x000000010e1a5d68 -[AFURLSessionManager dataTaskWithRequest:completionHandler:] (AFURLSessionManager.m:664) 
11 Snagit        0x000000010e19083e -[AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:success:failure:] (AFHTTPSessionManager.m:243) 
12 Snagit        0x000000010e18fb0d -[AFHTTPSessionManager GET:parameters:success:failure:] (AFHTTPSessionManager.m:112) 
13 Snagit        0x000000010e1d2f29 __51-[TSCAccountHTTPSession GET:parameters:completion:]_block_invoke (TSCAccountHTTPSession.m:317) 
14 Snagit        0x000000010e1d464f __58-[TSCAccountHTTPSession performNetworkRequest:completion:]_block_invoke_2 (TSCAccountHTTPSession.m:495) 
15 libdispatch.dylib     0x00007fffab375f5f _dispatch_call_block_and_release + 12 
16 libdispatch.dylib     0x00007fffab36d128 _dispatch_client_callout + 8 
17 libdispatch.dylib     0x00007fffab37c2ce _dispatch_queue_override_invoke + 743 
18 libdispatch.dylib     0x00007fffab36eee0 _dispatch_root_queue_drain + 476 
19 libdispatch.dylib     0x00007fffab36ecb7 _dispatch_worker_thread3 + 99 
20 libsystem_pthread.dylib    0x00007fffab5b9746 _pthread_wqthread + 1299 
21 libsystem_pthread.dylib    0x00007fffab5b9221 start_wqthread + 13 




Thread 13: 
0 libsystem_kernel.dylib    0x00007fffab4d23b6 __ulock_wait + 10 
1 libdispatch.dylib     0x00007fffab385c6e _dispatch_thread_event_wait_slow + 85 
2 libdispatch.dylib    --->0x00007fffab3785ea _dispatch_barrier_sync_f_slow + 402 
3 Snagit        0x000000010e1a5d68 -[AFURLSessionManager dataTaskWithRequest:completionHandler:] (AFURLSessionManager.m:664) 
4 Snagit        0x000000010e19083e -[AFHTTPSessionManager dataTaskWithHTTPMethod:URLString:parameters:success:failure:] (AFHTTPSessionManager.m:243) 
5 Snagit        0x000000010e18fb0d -[AFHTTPSessionManager GET:parameters:success:failure:] (AFHTTPSessionManager.m:112) 
6 Snagit        0x000000010e1d2f29 __51-[TSCAccountHTTPSession GET:parameters:completion:]_block_invoke (TSCAccountHTTPSession.m:317) 
7 Snagit        0x000000010e1d464f __58-[TSCAccountHTTPSession performNetworkRequest:completion:]_block_invoke_2 (TSCAccountHTTPSession.m:495) 
8 libdispatch.dylib     0x00007fffab375f5f _dispatch_call_block_and_release + 12 
9 libdispatch.dylib     0x00007fffab36d128 _dispatch_client_callout + 8 
10 libdispatch.dylib     0x00007fffab37c2ce _dispatch_queue_override_invoke + 743 
11 libdispatch.dylib     0x00007fffab36eee0 _dispatch_root_queue_drain + 476 
12 libdispatch.dylib     0x00007fffab36ecb7 _dispatch_worker_thread3 + 99 
13 libsystem_pthread.dylib    0x00007fffab5b9746 _pthread_wqthread + 1299 
14 libsystem_pthread.dylib    0x00007fffab5b9221 start_wqthread + 13 

Und hier ist der AFNetworking Code, der die dispatch_sync hat:

- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request 
          completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 
{ 
    __block NSURLSessionDataTask *dataTask = nil; 
    dispatch_sync(
     url_session_manager_creation_queue(), ^{ 
     dataTask = [self.session dataTaskWithRequest:request]; 
     } 
    ); 

    [self addDelegateForDataTask:dataTask completionHandler:completionHandler]; 

    return dataTask; 
} 

static dispatch_queue_t url_session_manager_creation_queue() { 
    static dispatch_queue_t af_url_session_manager_creation_queue; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL); 
    }); 

    return af_url_session_manager_creation_queue; 
} 

Antwort

4

ich hoffe, dass die folgenden beantwortet Ihre Frage. Wenn Sie jedoch einen Fehler in Ihrem Programm haben, den Sie zu debuggen versuchen, und es ist die Tatsache, dass die gleiche Anfrage zweimal gemacht wird, dann ist dies nicht der Code, der den Fehler enthalten würde.

GCD verwendet die so genannten Barrieren, die Blöcke auf einer Absende-Warteschlange zu synchronisieren, in der Dokumentation einen Blick hier: Dispatch und dispatch_barrier_async

Eine Barriere in der Warteschlange gegenseitige Exklusivität des Sperrblocks gewährleisten, dh es führt alles alleine aus.

Eine Dispatcherbarriere ermöglicht das Erstellen eines Synchronisationspunkts in einer Warteschlange für gleichzeitige Dispatchs. Wenn sie auf eine Barriere trifft, verzögert eine gleichzeitige Warteschlange die Ausführung des Barriereblocks (oder irgendwelcher weiterer Blöcke), bis alle Blöcke, die vor der Sperre eingereicht wurden, beendet sind. An diesem Punkt wird der Sperrblock von selbst ausgeführt. Nach Beendigung nimmt die Warteschlange ihr normales Ausführungsverhalten wieder auf.

Wenn die Warteschlange seriell oder globale gleichzeitig ein, dann gilt:

Von dispatch_barrier_sync: Wenn die Warteschlange an diese Funktion übergeben eine serielle Warteschlange oder einer der globalen gleichzeitige Warteschlangen ist, Diese Funktion verhält sich wie die Funktion dispatch_sync.

In der Tat dispatch_sync Delegierten dispatch_barrier_sync_* und der Call-Stack wie folgt aussehen würde:

// some inline functions omitted here 
_dispatch_barrier_sync_f_invoke 
_dispatch_barrier_sync_f 
dispatch_sync_f 
dispatch_sync 

Wenn nun auf dem Weg, die Laufzeit erwerben nicht die Barriere für den aktuellen Thread für einen anderen Block, dann dauert es die slow Straße. Dadurch wird die gesamte Synchronisation für Sie eingerichtet und der Thread des Aufrufers wartet. Auf der event, dass die Warteschlange wieder frei ist, wird der Thread fortgesetzt und der nächste Block ausgeführt.

Im Grunde ist es das gleiche Call-Stack, aber mit einem Umweg auf dem Weg, mit einigen Schloss (Semaphore), die dann zurück zu _dispatch_barrier_sync_f_invoke führt:

// again, some inline functions omitted here 
_dispatch_barrier_sync_f_invoke 
_dispatch_thread_event_wait 
_dispatch_barrier_sync_f_slow 
// here _dispatch_queue_try_acquire_barrier_sync fails... 
_dispatch_barrier_sync_f 
dispatch_sync_f 
dispatch_sync 

Wenn Sie mehr über GCD erfahren möchten, dann ist der beste Ort, um die Interna zu verstehen, der Quellcode repository on GitHub