mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 04:17:17 +00:00
docs: image url
This commit is contained in:
@@ -315,7 +315,7 @@ dispatch_sync(dispatch_get_main_queue(), nil);
|
||||
|
||||
Demo1
|
||||
|
||||
<img src="./../assets/RunloopPerformSelector.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelector.png" style="zoom:25%" />
|
||||
|
||||
QA:为什么先打印1、3再打印2?
|
||||
|
||||
@@ -332,7 +332,7 @@ Demo2:
|
||||
|
||||
|
||||
|
||||
<img src="./../assets/RunloopPerformSelectorAfterDelay.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelectorAfterDelay.png" style="zoom:25%" />
|
||||
|
||||
|
||||
|
||||
@@ -372,13 +372,13 @@ QA:为什么 test 里的2没有打印?
|
||||
|
||||
所以代码改下就可运行。
|
||||
|
||||
<img src="./../assets/RunloopPerformSelectorAfterDelayFix.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelectorAfterDelayFix.png" style="zoom:25%" />
|
||||
|
||||
|
||||
|
||||
注意:可能有一部分人会这么在子线程中添加 RunLoop,会存在3无法打印的问题。为什么?
|
||||
|
||||
<img src="./../assets/RunloopPerformSelectorAfterDelayFix1.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelectorAfterDelayFix1.png" style="zoom:25%" />
|
||||
|
||||
`[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];` 本质上让 RunLoop 在指定模式下运行,直到发生以下情况之一:
|
||||
|
||||
@@ -391,15 +391,15 @@ QA:为什么 test 里的2没有打印?
|
||||
|
||||
第一种:在子线程方法中,手动关闭子线程中的 RunLoop
|
||||
|
||||
<img src="./../assets/RunloopPerformSelectorAfterDelayFix2.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelectorAfterDelayFix2.png" style="zoom:25%" />
|
||||
|
||||
第二种:不要用 `[NSDate distantFuture]`,设置个0秒也可以,改为 `[NSDate dateWithTimeIntervalSinceNow:0]]`
|
||||
|
||||
<img src="./../assets/RunloopPerformSelectorAfterDelayFix3.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelectorAfterDelayFix3.png" style="zoom:25%" />
|
||||
|
||||
第三种:不要用 `[NSDate distantFuture]`,设置个0秒也可以,改为 `[NSDate dateWithTimeIntervalSinceNow:0]]`。另外不要加 Port,直接在子线程中先获取一次 RunLoop 就好,因为 ``performSelector...withObject...afterDelay...` ` 已经给当前的 RunLoop 添加了 NSTimer,只是没有开启。 分析 RunLoop 源码分析后会发现,在子线程中获取一次 RunLoop,会默认创建一个 RunLoop。
|
||||
|
||||
<img src="./../assets/RunloopPerformSelectorAfterDelayFix4.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/RunloopPerformSelectorAfterDelayFix4.png" style="zoom:25%" />
|
||||
|
||||
所以要研究 iOS 底层的同学,看看 **GUNStep 代码吧,这是宝藏**
|
||||
|
||||
@@ -409,13 +409,13 @@ QA:为什么 test 里的2没有打印?
|
||||
|
||||
Demo1:
|
||||
|
||||
<img src="./../assets/GCDThreadWillTerminateWhenBlockFinished.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/GCDThreadWillTerminateWhenBlockFinished.png" style="zoom:30%" />
|
||||
|
||||
同理,GCD 虽然开启了子线程,但是 Block 结束后,线程也就结束了。所以线程任务中的1秒后的任务肯定也结束了。
|
||||
|
||||
Demo2:
|
||||
|
||||
<img src="./../assets/NSThreadWillTerminateSoCannotUse.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSThreadWillTerminateSoCannotUse.png" style="zoom:25%" />
|
||||
|
||||
可以看到 NSThread 里的 block 执行结束后,thread 结束了。后面的 performSelector 想在线程里执行任务,就会 crash。
|
||||
|
||||
@@ -528,7 +528,7 @@ static void *nsthreadLauncher(void *thread) {
|
||||
|
||||
所以解决办法也是在线程的 block 里面加 RunLoop,让它保活
|
||||
|
||||
<img src="./../assets/NSThreadWillTerminateSoCanUseViaRunLoopPort.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSThreadWillTerminateSoCanUseViaRunLoopPort.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -569,7 +569,7 @@ dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
});
|
||||
```
|
||||
|
||||
<img src="./../assets/DispatchgroupNotify.png" style="zoom:50%"/>
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/DispatchgroupNotify.png" style="zoom:50%"/>
|
||||
|
||||
|
||||
|
||||
@@ -577,7 +577,7 @@ dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
|
||||
### 经典 Demo
|
||||
|
||||
<img src="./../assets/BlockAndQueue.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/BlockAndQueue.png" style="zoom:30%" />
|
||||
|
||||
会输出什么?
|
||||
|
||||
@@ -802,21 +802,21 @@ si:step instruction,简写为 stepi,si。当你在 Xcode 汇编面板看
|
||||
|
||||
第一步:当第二次调用 saveMoney 方法,开启汇编调试
|
||||
|
||||
<img src="./../assets/OSSpinLock-Assemble2.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/OSSpinLock-Assemble2.png" style="zoom:30%" />
|
||||
|
||||
看到可疑方法 `OSSpinLockLock`,给它加断点,看到第10行高亮了。lldb 模式输入 c,敲回车。次数输入 si 即可进入 `OSSpinLockLock` 方法内部调试
|
||||
|
||||
第二步:继续输入 si,敲回车
|
||||
|
||||
<img src="./../assets/OSSpinLock-Assemble3.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/OSSpinLock-Assemble3.png" style="zoom:30%" />
|
||||
|
||||
第三步:看到可疑方法 `_OSSpinLockLockSlow`,给它加断点,lldb 输入 C。此时断点到这一行了,继续输入 si。
|
||||
|
||||
<img src="./../assets/OSSpinLock-Assemble4.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/OSSpinLock-Assemble4.png" style="zoom:30%" />
|
||||
|
||||
第四步:在 `OSSpinLockLockSlow` 方法内部调试,不断输入 si。
|
||||
|
||||
<img src="./../assets/OSSpinLockAssemble1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/OSSpinLockAssemble1.png" style="zoom:30%" />
|
||||
|
||||
发现不断 si 最终一直会在第6行到第19行之间执行。懂汇编的会发现这其实是一个 while 循环。便可以证明自旋锁 OSSpinLock 在等锁的时候,底层实现是执行 while 循环,忙等,“太浪费性能了”(如果使用锁资源的线程任务很简单,那自旋也是高效的,可以快速获取锁。)
|
||||
|
||||
@@ -915,26 +915,26 @@ int cursorr = 1;
|
||||
|
||||
假如对存钱过程,忘记解锁怎么办?产生死锁,如下
|
||||
|
||||
<img src="./../assets/Thread-deadlock-unfaillock.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/Thread-deadlock-unfaillock.png" style="zoom:30%" />
|
||||
|
||||
添加 cursor 标记死锁是发生在 `saveMoney` 方法执行的第几次。发现是第二次。因为第一次锁没有任何使用方,所以加锁成功,当第二次加锁的时候发现锁没有释放,所以产生死锁。
|
||||
|
||||
这时候使用尝试加锁 API `os_unfair_lock_trylock` 即可成功如下
|
||||
|
||||
<img src="./../assets/Thread-deadlock-unfairTrylock.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/Thread-deadlock-unfairTrylock.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
#### 汇编剖析实现原理
|
||||
|
||||
同样方式看看 ,按照上述调试汇编代码的步骤,我将关键步骤截图如下
|
||||
<img src="./../assets/osunfairlock-assemble1.png" style="zoom:30%" />
|
||||
<img src="./../assets/osunfairlock-assemble2.png" style="zoom:30%" />
|
||||
<img src="./../assets/osunfairlock-assemble3.png" style="zoom:30%" />
|
||||
<img src="./../assets/osunfairlock-assemble4.png" style="zoom:30%" />
|
||||
<img src="./../assets/osunfairlock-assemble5.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/osunfairlock-assemble1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/osunfairlock-assemble2.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/osunfairlock-assemble3.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/osunfairlock-assemble4.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/osunfairlock-assemble5.png" style="zoom:30%" />
|
||||
|
||||
<img src="./../assets/osunfairlock-assemble6.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/osunfairlock-assemble6.png" style="zoom:30%" />
|
||||
|
||||
结论:可以看到 `os_unfair_lock` 在锁等待的时候,底层调用的是 `sysCall`,当这一步执行后会发现后续代码都不执行了,也就是调用系统底层能力,线程真正休眠了,而不是一个循环忙等的实现,所以性能好。
|
||||
|
||||
@@ -985,7 +985,7 @@ pthread_mutex_destroy(&_moneyLock);
|
||||
|
||||
使用如下
|
||||
|
||||
<img src="./../assets/PThreadMutextLock.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutextLock.png" style="zoom:25%" />
|
||||
|
||||
#### 化身递归锁
|
||||
|
||||
@@ -1033,7 +1033,7 @@ pthread_mutex_destroy(&_moneyLock);
|
||||
|
||||
改进后的效果如下
|
||||
|
||||
<img src="./../assets/PThreadMutextRecursiveLock.png" style="zoom:25%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutextRecursiveLock.png" style="zoom:25%" />
|
||||
|
||||
|
||||
|
||||
@@ -1045,33 +1045,33 @@ QA:互斥递归锁,可以在不同线程中加锁吗?
|
||||
|
||||
#### 汇编剖析实现原理
|
||||
|
||||
<img src="./../assets/PThreadMutexLock1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock1.png" style="zoom:30%" />
|
||||
|
||||
输入 si 继续跟进,可以看到还是在执行我们自己的代码,LockExplore image 的 `pthread_mutex_lock` 方法
|
||||
|
||||
<img src="./../assets/PThreadMutexLock2.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock2.png" style="zoom:30%" />
|
||||
|
||||
继续输入 si 跟进
|
||||
|
||||
<img src="./../assets/PThreadMutexLock3.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock3.png" style="zoom:30%" />
|
||||
|
||||
可以看到此时调用到系统 `libsystem_pthread.dylib` 库的 `pthread_mutex_lock` 方法了。
|
||||
|
||||
第41行看到关键函数,继续输入 si 进去看看
|
||||
|
||||
<img src="./../assets/PThreadMutexLock4.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock4.png" style="zoom:30%" />
|
||||
|
||||
可以看到内部第62行关键函数调用了 `_pthread_mutex_firstfit_lock_wait` 方法。此时继续输入 si 跟踪看看
|
||||
|
||||
<img src="./../assets/PThreadMutexLock5.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock5.png" style="zoom:30%" />
|
||||
|
||||
可以看到内部第25行调用了关键函数 `__psynch_mutexwait`,继续输入 si 看看
|
||||
|
||||
<img src="./../assets/PThreadMutexLock6.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock6.png" style="zoom:30%" />
|
||||
|
||||
可以看到内部继续调用了系统 `libsystem_pthread.dylib` 库的 `__psynch_mutexwait` 方法。继续输入 si
|
||||
|
||||
<img src="./../assets/PThreadMutexLock7.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadMutexLock7.png" style="zoom:30%" />
|
||||
|
||||
可以看到内部第4行发生了系统调用 `sysCall`,执行完第四句指令,线程立马就结束了。
|
||||
|
||||
@@ -1256,7 +1256,7 @@ CocoaLumberjack 的 DDLog.m 中,锁返回值检查的严谨写法:
|
||||
|
||||
激活所有等待该条件的线程 `pthread_cond_broadcast(&_condition)`
|
||||
|
||||
<img src="./../assets/PThreadConditionLock.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadConditionLock.png" style="zoom:30%" />
|
||||
|
||||
可以看到同时调用 remove、add 方法
|
||||
|
||||
@@ -1358,13 +1358,13 @@ NSRecursiveLock 不能在多线程下递归调用。@synchronized 可以在多
|
||||
|
||||
Demo
|
||||
|
||||
<img src="./../assets/NSLockDemo.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSLockDemo.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
NSLock 死锁
|
||||
|
||||
<img src="./../assets/NSLockDeadLock.png" style="zoom:40%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSLockDeadLock.png" style="zoom:40%" />
|
||||
|
||||
会发生死锁,后续代码无法执行,App 表现就是 ANR。重复对 NSLock 进行加锁可能导致死锁问题,同时也可能引发数据竞争和性能下降等并发相关隐患
|
||||
|
||||
@@ -1414,7 +1414,7 @@ API
|
||||
|
||||
Demo:
|
||||
|
||||
<img src="./../assets/NSConditionLockDemo.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSConditionLockDemo.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -1426,7 +1426,7 @@ Demo:
|
||||
|
||||
疑问:调用 signal 方法后,另一个等待锁的地方会立马得到锁资源吗?可以做个实验,给 signal 后 sleep 2秒,再调用 unlock
|
||||
|
||||
<img src="./../assets/NSConditionOrder1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSConditionOrder1.png" style="zoom:30%" />
|
||||
|
||||
观察打印信息可以看到:
|
||||
|
||||
@@ -1438,7 +1438,7 @@ Demo:
|
||||
|
||||
|
||||
|
||||
<img src="./../assets/NSConditionOrder2.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSConditionOrder2.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -1479,7 +1479,7 @@ API 如下:
|
||||
|
||||
Demo
|
||||
|
||||
<img src="./../assets/NSConditionLockDemo1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/NSConditionLockDemo1.png" style="zoom:30%" />
|
||||
|
||||
分析:虽然通过3个线程,设置了线程的先后顺序,但是多线程任务执行的时候到底谁先执行,是没办法控制的。但是通过 `NSConditionLock lockWhenCondition:*` 的能力,可以控制线程的执行顺序。
|
||||
|
||||
@@ -1495,7 +1495,7 @@ Demo
|
||||
|
||||
线程同步的本质就是多线程的任务是顺序执行
|
||||
|
||||
<img src="./../assets/SerialQueueToSolveThreadSyn.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/SerialQueueToSolveThreadSyn.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -1509,11 +1509,11 @@ semaphore 叫做”信号量”
|
||||
|
||||
信号量的初始值为1,代表同时只允许1条线程访问资源,保证线程同步
|
||||
|
||||
<img src="./../assets/DispatchSemaphoreControlThreadCount1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/DispatchSemaphoreControlThreadCount1.png" style="zoom:30%" />
|
||||
|
||||
可以看到打印了20个线程,但是我们控制线程最大数量怎么办呢?可以用信号量实现。效果如下:
|
||||
|
||||
<img src="./../assets/DispatchSemaphoreControlThreadCount2.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/DispatchSemaphoreControlThreadCount2.png" style="zoom:30%" />
|
||||
|
||||
#### dispatch_semaphore_wait 原理
|
||||
|
||||
@@ -1527,7 +1527,7 @@ semaphore 叫做”信号量”
|
||||
|
||||
所以如何让线程同步?设置信号量的值=1即可。保证同一时间只有一个线程任务在执行。代码如下
|
||||
|
||||
<img src="./../assets/SemaphoreMethodToControlThreadSync.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/SemaphoreMethodToControlThreadSync.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -1587,7 +1587,7 @@ dispatch_semaphore_signal(semaphore);
|
||||
|
||||
`@synchronized` 使用很方便,它是对 `pthread_mutex_t` 递归锁的封装。Demo 如下
|
||||
|
||||
<img src="./../assets/SynchronizedControlThreadSync.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/SynchronizedControlThreadSync.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -1595,9 +1595,9 @@ dispatch_semaphore_signal(semaphore);
|
||||
|
||||
为了探究下实现,开启汇编调试
|
||||
|
||||
<img src="./../assets/synchronized-asemble1.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/synchronized-asemble1.png" style="zoom:30%" />
|
||||
|
||||
<img src="./../assets/synchronized-asemble2.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/synchronized-asemble2.png" style="zoom:30%" />
|
||||
|
||||
通过汇编可以看到 `@synchronized` 底层调用了 `objc_sync_enter` 方法,其中又调用了 `id2data` 和 `os_unfair_recursive_lock_lock_with_options` 方法。 可以查看 objc4 的源码(笔者的 objc 版本为 objc4-objc4-912.3),查找 `objc_sync_enter`
|
||||
|
||||
@@ -2106,7 +2106,7 @@ pthread_rwlock_init(&_lock, NULL)
|
||||
|
||||
Demo
|
||||
|
||||
<img src="./../assets/PThreadRWLockDemo.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/PThreadRWLockDemo.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -2134,7 +2134,7 @@ dispatch_barrier_async(self.queue, ^{
|
||||
|
||||
上 Demo
|
||||
|
||||
<img src="./../assets/DispatchBarrierReadWriteDemo.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/DispatchBarrierReadWriteDemo.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -2163,7 +2163,7 @@ Demo
|
||||
}
|
||||
```
|
||||
|
||||
<img src="./../assets/GCDBarrierCannotHoldGlobalQueue.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/GCDBarrierCannotHoldGlobalQueue.png" style="zoom:30%" />
|
||||
|
||||
|
||||
|
||||
@@ -2186,7 +2186,7 @@ Demo
|
||||
}
|
||||
```
|
||||
|
||||
<img src="./../assets/GCDBarrierCanHoldCustomQueue.png" style="zoom:30%" />
|
||||
<img src="https://raw.githubusercontent.com/FantasticLBP/knowledge-kit/master/assets/GCDBarrierCanHoldCustomQueue.png" style="zoom:30%" />
|
||||
|
||||
结论:可以发现 GCD `dispatch_barrier_async` 栅栏函数,拦不住全局队列,却可以拦住自己创建的普通队列。这是为什么?
|
||||
|
||||
|
||||
Reference in New Issue
Block a user