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

A O*_*A O 2 macos multithreading grand-central-dispatch

因此,我的应用程序当前可以最终处于发出网络请求的状态,并且可以在第一个请求仍在等待响应时发出另一个相同的请求

至少我认为。按照这个逻辑,看起来线程 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
Run Code Online (Sandbox Code Playgroud)

这是具有以下内容的 AFNetworking 代码dispatch_sync

- (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;
}
Run Code Online (Sandbox Code Playgroud)

小智 6

I hope the following does answer your question. However, if you have an error in your program that you are trying to debug, and it is the fact, that the same request is being made twice, then this is not the code that would contain the error.

GCD uses the so called barriers to synchronize the blocks on a dispatch queue, take a look at the documentation here: Dispatch and dispatch_barrier_async

A barrier ensure mutual exclusiveness of the barrier block on the queue, i.e. it executes all alone by itself.

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.

If the queue is serial, or global concurrent one, then:

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.

In fact dispatch_sync delegates to dispatch_barrier_sync_* and the call stack would look something like this:

// some inline functions omitted here
_dispatch_barrier_sync_f_invoke
_dispatch_barrier_sync_f
dispatch_sync_f
dispatch_sync
Run Code Online (Sandbox Code Playgroud)

现在,如果在此过程中运行时无法为另一个块获取当前线程的屏障,那么它会走这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
Run Code Online (Sandbox Code Playgroud)

如果您想了解更多有关GCD,那么了解内部结构的最佳位置是其GitHub 上的源代码存储库