- 队列:串行队列,并发队列,全局队列,主队列。
2.执行的方法有:同步执行和异步执行。
- 多线程,四种,pthread,NSthread,GCD,NSOperation,phtread是跨平台的。GCD和NSOperation都是常用的,后者是基于前者。
4.任务和队列 一定要分清楚 1》任务:其实就是一段想要执行的代码,在GCD中就是Block,就是C代码的闭包实现 2〉任务的执行方式同步执行 和 异步执行也就是 是否具有开线程的能力。队列就是用于任务存放有串行队列 和 并行队列。
同步任务
-(void)syncqueue{
dispatch_queue_t globalqueue = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurentqueue = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"同步任务1--%@-",[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"同步任务2--%@-",[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"同步任务3--%@-",[NSThreadcurrentThread]);
});
dispatch_sync(globalqueue, ^{
NSLog(@"主队列----同步任务4 --%@-",[NSThreadcurrentThread]);
});
dispatch_sync(globalqueue, ^{
NSLog(@"主队列----同步任务5 --%@-",[NSThreadcurrentThread]);
});
dispatch_sync(concurentqueue, ^{
NSLog(@"全局队列----同步任务6 --%@-",[NSThreadcurrentThread]);
});
dispatch_sync(concurentqueue, ^{
NSLog(@"全局队列----同步任务7 --%@-",[NSThreadcurrentThread]);
});
NSLog(@"-123-%@-",[NSThread currentThread]);
/*
同步任务1--{number = 1, name = main}-
2019-11-07 10:01:24.674 YJApiRequestTool[9897:82003] 同步任务2--{number = 1, name = main}-
2019-11-07 10:01:24.674 YJApiRequestTool[9897:82003] 同步任务3--{number = 1, name = main}-
2019-11-07 10:01:24.674 YJApiRequestTool[9897:82003] 全局队列----同步任务4 --{number = 1, name = main}-
2019-11-07 10:01:24.674 YJApiRequestTool[9897:82003] 全局队列----同步任务5 --{number = 1, name = main}-
2019-11-07 10:01:24.675 YJApiRequestTool[9897:82003] -123-{number = 1, name = main}
打印信息分析: 主队列与全局队列 只在主线程执行 还有自己创建的队列 都在主线程完成的。并没有开辟新的线程 这里注意一点 只是任务的执行顺序 并不代表任务执行完成才去执行下面的任务(这里你可以写一个延时任务测试)。下面会再次讲述关于任务完成等待再执行下面任务。
这里面没有用到 主队列 会死锁 死锁原因: 遵循 先进先出原则 FIFO 同步任务又会依次执行 相互等待
*/
}
异步任务
//异步----串行队列/并发队列 ----
-(void)asyncqueue{
//主队列
dispatch_queue_t mainqueue = dispatch_get_main_queue();
//全局队列
dispatch_queue_t globalqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_queue_t queue = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t concurentqueue = dispatch_queue_create("queue2", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"异步任务1--%@-",[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"异步任务2--%@-",[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"异步任务3--%@-",[NSThreadcurrentThread]);
});
dispatch_async(globalqueue, ^{
NSLog(@"全局队列----异步任务4 --%@-",[NSThreadcurrentThread]);
});
dispatch_async(globalqueue, ^{
NSLog(@"全局队列----异步任务5 --%@-",[NSThreadcurrentThread]);
});
dispatch_async(mainqueue, ^{
NSLog(@"主队列---异步任务6 --%@-",[NSThreadcurrentThread]);
});
dispatch_async(mainqueue, ^{
NSLog(@"主队列----异步任务7 --%@-",[NSThreadcurrentThread]);
});
dispatch_async(concurentqueue, ^{
NSLog(@"--异步任务8 --%@-",[NSThreadcurrentThread]);
});
dispatch_async(concurentqueue, ^{
NSLog(@"--异步任务9 --%@-",[NSThreadcurrentThread]);
});
NSLog(@"-123-%@-",[NSThread currentThread]);
/*
-123-{number = 1, name = main}-
2019-11-07 10:32:24.964 YJApiRequestTool[10683:104110] 全局队列----异步任务5 --{number = 4, name = (null)}-
2019-11-07 10:32:24.964 YJApiRequestTool[10683:104108] 异步任务1--{number = 2, name = (null)}-
2019-11-07 10:32:24.964 YJApiRequestTool[10683:104130] --异步任务8 --{number = 5, name = (null)}-
2019-11-07 10:32:24.964 YJApiRequestTool[10683:104106] 全局队列----异步任务4 --{number = 3, name = (null)}-
2019-11-07 10:32:24.964 YJApiRequestTool[10683:104131] --异步任务9 --{number = 6, name = (null)}-
2019-11-07 10:32:24.965 YJApiRequestTool[10683:104108] 异步任务2--{number = 2, name = (null)}-
2019-11-07 10:32:24.965 YJApiRequestTool[10683:104108] 异步任务3--{number = 2, name = (null)}-
2019-11-07 10:32:25.027 YJApiRequestTool[10683:104067] 主队列---异步任务6 --{number = 1, name = main}-
2019-11-07 10:32:25.027 YJApiRequestTool[10683:104067] 主队列----异步任务7 --{number = 1, name = main}-
可以看到 会开辟新的线程 在细心看下又会发现
串行队列 :只开辟了一个线程 存放了三个任务
并行队列 :这个开辟了多个线程
主队列:依然在主线程
全局队列:开辟新线程
得知结果: 异步任务 串行队列 开辟一个新线程 任务依次执行 ,并发队列开辟多个新线程
这里注意一点 只是任务的执行顺序 并不代表任务执行完成才去执行下面的任务
*/
}
再稍微复杂一些的 GCD中的API
这里需要模拟一些场景
场景一 2个任务 先执行完 再执行第三个任务 这里考虑任务等待 (注意)场景是前面任务执行完
方式1.借助 dispatch_group_t 全局队列
-(void)grupqueue{
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, q, ^{
NSLog(@"任务1开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务1完成");
dispatch_group_leave(group);
});
});
dispatch_group_async(group, q, ^{
NSLog(@"任务2开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务2完成");
dispatch_group_leave(group);
});
});
dispatch_group_enter(group);
dispatch_group_enter(group);
dispatch_group_notify(group, q, ^{
NSLog(@"任务3开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务3完成");
});
});
/*
2019-11-09 14:51:19.161 YJApiRequestTool[3863:120062] 任务2开始
2019-11-09 14:51:19.161 YJApiRequestTool[3863:120061] 任务1开始
2019-11-09 14:51:21.162 YJApiRequestTool[3863:120028] 任务2完成
2019-11-09 14:51:22.453 YJApiRequestTool[3863:120028] 任务1完成
2019-11-09 14:51:22.454 YJApiRequestTool[3863:120062] 任务3开始
2019-11-09 14:51:23.513 YJApiRequestTool[3863:120028] 任务3完成
有打印数据分析知:任务1任务2执行完后才会执行任务3 而且 任务1与任务2执行是没有顺序的。1与2执行完后才会执行
dispatch_group_enter(group); dispatch_group_leave(group);这是成对存在的。少一个都不行需要注意。其实他就是一个等待的过程。也可以理解为信号。发送信号才执行。所以也可以使用信号量去做
*/
}
方式2.借助 dispatch_group_t dispatch_semaphore_t 子线程执行 全局并发队列 注意函数是执行完成 即便是耗时任务 任务1 与2 执行无顺序 执行完再执行3
-(void)otherGrupqueue{
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_group_async(group, q, ^{
NSLog(@"任务1开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务1完成");
dispatch_semaphore_signal(semaphore);
});
});
dispatch_group_async(group, q, ^{
NSLog(@"任务2开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务2完成");
dispatch_semaphore_signal(semaphore);
});
});
dispatch_group_notify(group, q, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务3开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务3完成");
});
});
/*
这里只说下 dispatch_semaphore_t 他就是信号量 等待信号 发送信号 0与1的操作 执行dispatch_semaphore_wait -1 执行dispatch_semaphore_signal+1
*/
}
场景2 俩个任务 依次执行 并且执行完后再执行第二个 与场景1不同的是任务1与任务2 依次执行完成 其实很简单的 上面任务 坐下改动就行了
dispatch_semaphore_t 信号量
//方式1
-(void)grupqueue{
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_group_async(group, q, ^{
NSLog(@"任务1开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务1完成");
dispatch_semaphore_signal(semaphore);
});
});
dispatch_group_async(group, q, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务2开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务2完成");
dispatch_semaphore_signal(semaphore);
});
});
dispatch_group_notify(group, q, ^{
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务3开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务3完成");
});
});
/*
2019-11-09 15:15:08.053 YJApiRequestTool[4395:138033] 任务1开始
2019-11-09 15:15:11.053 YJApiRequestTool[4395:137999] 任务1完成
2019-11-09 15:15:11.054 YJApiRequestTool[4395:138032] 任务2开始
2019-11-09 15:15:13.199 YJApiRequestTool[4395:137999] 任务2完成
2019-11-09 15:15:13.199 YJApiRequestTool[4395:138032] 任务3开始
2019-11-09 15:15:14.235 YJApiRequestTool[4395:137999] 任务3完成
*/
}
//方式2
- (void)configDispatch_semaphore {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 创建信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(queue, ^{
NSLog(@"任务1开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务1完成");
dispatch_semaphore_signal(semaphore);
});
});
dispatch_async(queue, ^{
dispatch_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务2开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务2完成");
dispatch_semaphore_signal(semaphore);
});
});
dispatch_async(queue, ^{
dispatch_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"任务3开始");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"任务3完成");
dispatch_semaphore_signal(semaphore);
});
});
}
讲述栅栏函数
dispatch_barrier_async 栅栏函数 前面的函数执行完后才会执行下面的函数 (个人使用的比较少) 他很好理解 就是门槛的意思 但是注意一点 dispatch_get_global_queue(0, 0) 这里讲述的函数执行完 与任务执行完成 这是俩个概念的。
- (void)configDispatch_barrier {
// dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"执行第一个任务--%@",[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"执行第二个任务--%@",[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"执行第三个任务--%@",[NSThreadcurrentThread]);
});
dispatch_barrier_async(queue, ^{
NSLog(@"我是栅栏,前边的任务都执行完了,在执行下边的任务--%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"执行第四个任务--%@",[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"执行第五个任务--%@",[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"执行第六个任务--%@",[NSThreadcurrentThread]);
});
}
//个人认为 同步函数的作用 对于全局队列 无效
深入一下理解
场景3 模拟网络请求 一个一个的执行 用信号量
//示例1
- (void)chainRequestCurrentConfig {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray*list =@[@"1",@"2",@"3"];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[listenumerateObjectsUsingBlock:^(id _Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {
[self fetchConfigurationWithCompletion:^(NSDictionary *dict) {
dispatch_semaphore_signal(semaphore);
}];
NSLog(@"%@",obj);
dispatch_semaphore_wait(semaphore,DISPATCH_TIME_FOREVER);
}];
});
}
- (void)fetchConfigurationWithCompletion:(void(^)(NSDictionary*dict))completion {
//AFNetworking或其他网络请求库
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//模拟网络请求
sleep(2);
!completion ?nil: completion(nil);
});
}
//示例2 场景 :我们定义一个有返回值的函数 但是这个函数获取得到的返回值比较耗时。我们可以这样写 (其实实现方式太多了) 这里说个关键点dispatch_semaphore_t
-(NSString*)home{
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
__block NSString *name=@"";
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
name = @"111";
dispatch_semaphore_signal(semaphore);
});
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return name;
}
场景4 模拟网络请求 一个一个的执行 这个时候 模拟网络请求不考虑谁先执行完成。只在意 所有的网络请求执行完后 去刷新列表
-(void)requestData{
dispatch_queue_t que = dispatch_get_global_queue(0, 0);
dispatch_group_t grup = dispatch_group_create();
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (int a=0; a<6; a++) {
NSLog(@"请求任务%zd开始",a);
dispatch_group_async(grup, que, ^{
[self requesthome:a :grup];
NSLog(@"请求任务%zd完成",a);
});
}
dispatch_group_notify(grup, que, ^{
NSLog(@"循环完了");
});
});
}
-(void)requesthome:(NSInteger)count :(dispatch_group_t)grup{
dispatch_group_enter(grup);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*count * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
NSLog(@"---%zd---",count);
dispatch_group_leave(grup);
});
});
}
/*
2019-11-09 15:44:22.773 YJApiRequestTool[5017:158925] 请求任务0开始
2019-11-09 15:44:22.773 YJApiRequestTool[5017:158925] 请求任务1开始
2019-11-09 15:44:22.773 YJApiRequestTool[5017:158924] 请求任务0完成
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158927] ---0---
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158925] 请求任务2开始
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158931] 请求任务1完成
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158925] 请求任务3开始
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158927] 请求任务2完成
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158931] 请求任务3完成
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158925] 请求任务4开始
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158925] 请求任务5开始
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158931] 请求任务4完成
2019-11-09 15:44:22.774 YJApiRequestTool[5017:158925] 请求任务5完成
2019-11-09 15:44:24.774 YJApiRequestTool[5017:158925] ---1---
2019-11-09 15:44:27.162 YJApiRequestTool[5017:158925] ---2---
2019-11-09 15:44:29.372 YJApiRequestTool[5017:158931] ---3---
2019-11-09 15:44:31.560 YJApiRequestTool[5017:158925] ---4---
2019-11-09 15:44:33.761 YJApiRequestTool[5017:158925] ---5---
2019-11-09 15:44:33.761 YJApiRequestTool[5017:158925] 循环完了
*/
额外用法
利用GCD来创建多线程 还是很方便的 这里特此 记录 整理也加深印象 接下来就是 定时任务 GCD
定时器
-(void)startTimer{
__block int count = 0;
// 获得队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
// 设置定时器的各种属性(几时开始任务,每隔多长时间执行一次)
// GCD的时间参数,一般是纳秒(1秒 == 10的9次方纳秒)
// 何时开始执行第一个任务
// dispatch_time(DISPATCH_TIME_NOW, 1.0 * NSEC_PER_SEC) 比当前时间晚3秒
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));//等待执行时间
uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);//定时间隔时间
dispatch_source_set_timer(self.timer, start, interval, 0);
// 设置回调
dispatch_source_set_event_handler(self.timer, ^{
NSLog(@"------------%@", [NSThread currentThread]);
count++;
if (count == 2) {
// 取消定时器
dispatch_cancel(self.timer);
self.timer = nil;
}
});
// 启动定时器
dispatch_resume(self.timer);
}
利用 GCD进行for循环
- (void)apply {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"apply---begin");
dispatch_apply(6, queue, ^(size_t index) {
NSLog(@"%zd---%@",index, [NSThread currentThread]);
});
NSLog(@"apply---end");
}
//同步
-(void)applyarray{
//1.创建NSArray类对象
NSArray *array = @[@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j"];
//2.创建一个全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//3.通过dispatch_apply函数对NSArray中的全部元素进行处理,并等待处理完成,
dispatch_apply([array count], queue, ^(size_t index) {
NSLog(@"%zu: %@", index, [array objectAtIndex:index]);
});
NSLog(@"done");
}
//异步
-(void)asyneapplyarray{
//1.创建NSArray类对象
NSArray *array = @[@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j"];
//2.创建一个全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_apply([array count], queue, ^(size_t index) {
NSLog(@"%zu: %@", index, [array objectAtIndex:index]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"done");
});
});
}
常见的死锁问题
- (void)deadLockCase1 {
NSLog(@"1"); // 任务1
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2"); // 任务2
});
NSLog(@"3"); // 任务3
}// 2、3 相互等待 解决方式-----改为异步 或者 串行队列改为并发队列
- (void)deadLockCase2 {
dispatch_queue_t aSerialDispatchQueue = dispatch_queue_create("com.test.deadlock.queue", DISPATCH_QUEUE_SERIAL);
NSLog(@"1"); //任务1
dispatch_sync(aSerialDispatchQueue, ^{
NSLog(@"2"); //任务2
dispatch_sync(aSerialDispatchQueue, ^{
NSLog(@"3"); //任务3
});
NSLog(@"4"); //任务4
});
NSLog(@"5"); //任务5
} // 3、4 死锁 原因与第一个死锁现象一样 虽然开辟了一个子线程 但这个子线程 3.4相互等待 解决方法与第一个一样 同步改为异步 核心点 第二个必须异步 或者改为并发队列
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
NSLog(@"semaphore create!");
dispatch_async(dispatch_get_main_queue(), ^{
dispatch_semaphore_signal(semaphore);
NSLog(@"semaphore plus 1");
});
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"semaphore minus 1");
}//dispatch_semaphore_wait一直在等待dispatch_semaphore_signal改变信号量
这里讲述的只是实现方式 并没有仔细讲述各个API含义 对于各个含义网上的太多了,可以自己查询下 再来看这篇文章。接下来会讲述一个 线程安全问题。这个线程安全很值得去关注考虑。 以后会公开
有疑问或bug 很希望您提出来 感谢