`_dispatch_barrier_sync_f_invoke` 和 `_dispatch_barrier_sync_f_slow` 有什么作用?

What do `_dispatch_barrier_sync_f_invoke` and `_dispatch_barrier_sync_f_slow` do?

所以我的应用程序目前可能会处于发出网络请求的状态,并且在第一个请求仍在等待响应时可以发出另一个相同的请求

至少我是这么认为的。按照这个逻辑,看起来线程 11 首先启动,然后是线程 13。然后线程 13 看起来它正在等待,因为线程 11 仍在等待响应

线程 11 有:_dispatch_barrier_sync_f_invoke 线程 13 有:_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

这是具有 dispatch_sync:

的 AFNetworking 代码
- (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;
}

希望以下内容能回答您的问题。但是,如果您在尝试调试的程序中有错误,并且事实是同一个请求被发出两次,那么这不是包含错误的代码。

GCD 使用所谓的屏障来同步调度队列上的块,请查看此处的文档:Dispatch and dispatch_barrier_async

屏障确保屏障块在队列上的互斥性,即它自己单独执行。

A dispatch barrier allows you to create a synchronization point within a concurrent dispatch queue. When it encounters a barrier, a concurrent queue delays the execution of the barrier block (or any further blocks) until all blocks submitted before the barrier finish executing. At that point, the barrier block executes by itself. Upon completion, the queue resumes its normal execution behavior.

如果队列是串行的,或者是全局并发的,那么:

From dispatch_barrier_sync: If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_sync function.

实际上 dispatch_sync 委托给 dispatch_barrier_sync_* 并且调用堆栈看起来像这样:

// some inline functions omitted here
_dispatch_barrier_sync_f_invoke
_dispatch_barrier_sync_f
dispatch_sync_f
dispatch_sync

现在,如果在此过程中运行时无法为另一个块获取当前线程的屏障,那么它会走 slow 路。这为您设置了所有同步,调用者线程等待。在 event 队列再次空闲时,线程继续执行下一个块。

基本上它是同一个调用堆栈,但沿途绕了个弯,有一些锁(信号量),然后返回到 _dispatch_barrier_sync_f_invoke:

// 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

如果你想深入了解GCD,那么了解内部结构的最好地方就是它的源代码repository on GitHub