iOS 开发之 GCD解析(block 如何被添加进 queue 中,以及 block 执行)
2017-02-14 13:16
786 查看
GCD 是系统为我们提供的一套 c 语言的 API,可以用来进行多线程编程,下面一次来讲解一下 GCD 的相关 API
首先先来理解 几个概念
并发:在某一时间间隔内,有两个或者两个以上的任务一起执行(本质还是串行的,只不过按照时间片轮转的方式交替执行)。
异步:不用等待前面的执行完,会新开辟一条线程去执行该任务。
一次只能有一个任务运行
可以生成很多个,创建了多少个串行队列就生成了多少个线程,但是对于系统来说大量的创建串行队列,会浪费内存,引起大量的上下文切换,影响程序的响应性能
*. Concunrrent Dispatch Queue:并发队列
某一时间间隔里可以有多个任务同时运行
并发队列中并发任务的数量是由 XNU 内核的状态决定的
相对于串行队列,不管生成了多少个Concunrrent Dispatch Queue:,系统指挥管理有效的并发队列
当创建了多个并发队列的时候,各个队列之间是并发的。
*. Main Dispatch Queue:主队列
当程序开始运行时,系统会为我们创建一个主线程,诸葛主队列就在主线程里面,因为主线程只有一个,所以主队列也就只有一个,因此主队列是一个串行队列
被加入到主队列的任务,必须在主 runloop 中执行(runloop 与线程的关系请点这里runloop 与线程的关系)
主队列是由系统默认创建的,可以通过dispatch_get_main_queue()的方式来获取
对于界面的刷新是要放到主队列的.
*. Global Dispatch Queue:全局队列
一个全局队列,所有的应用程序都可以用,是并发的
Global Dispatch Queue:有四个优先级
*. 高优先级
*. 低优先级
*. 默认优先级
*. 后台优先级
由 XNU 内核管理的用于Global Dispatch Queue的的线程会将Global Dispatch Queue的的优先级作为线程的优先级。
当第二个参数是 NULL,创建的是串行队列
当第二个参数是DISPATCH_QUEUE_CONCURRENT,创建的是并发队列
会开启一个新的线程,来执行 block 中的内容,要是刷新界面需要切换到主队列
代码如下
会造成死锁(在回调的queue是main queue的前提下)
代码如下
应用1:不管是并行队列还是串行队列,当任务以异步的方式被添加到队列中,队列之间是并发的,要想让队列之间同步,可以将要同步的队列的目标队列设置为同一个,如下例子
可以看出两个队列交替打印,所以说队列之间是并发的
修改代码如下
可以看出test2在 test1完成以后 test2才开始执行
应用2:当一个任务被追加到不同的串行队列中,但是串行队列之间是并发的,可以通过设置优先级的方式让其同步执行
* 共同点:他之前的任务会在他之前完成,他之后的任务会等他在执行完后执行
* 不同点:dispatch_barrier_async后面的任务不会等他执行完再 被添加进 队列;dispatch_barrier_sync后面的任务会等他再执行完以后再添加 进队列
* 任务是 先添加进队列,但是并不是一添加进去就开始执行
2. 例子
从上面的例子中可以看出这两个的区别:其实不难理解,因为 async 是一部的,所以不会阻塞线程,但是 sync 会阻塞线程,所以同步和异步的区别是在这里体现的
dispatch_group_async和dispatch_barrier_async 对比
都会在其前面的任务完成之后再执行
但是dispatch_barrier_async得后面的任务是在他执行完后再执行
dispatch_group_async中没有加入组中的任务是在所有组中的任务完成以后再执行
dispatch_group_wait和 dispatch_group_noticy
dispatch_group_wait可以指定在 group 的任务再执行了几秒时候做某些反应
dispatch_group_noticy在 group 中的处理完再做
相当于操作系统中的 wait-sigal 操作,那个数组就是一个共享资源,只要有人在用(当 信号量计数为1),别的就会陷入等待,直到别人不用了,再去用,用之前先让计数-1,这样当别的人来用,就会知道有人在用,我还是等待吧,用完后,要记得让计数+1,释放这个资源,告诉别人这个资源我已经不用了,你可以用了**因为####7. dispatch_apply:让代码重复执行
应用:可以利用他来遍历数组
可以用来实现单例,线程安全
dispatch_resume让被挂起的 queue 继续执行。
不是一定时间后执行相应的任务,而是在一定时间后将其加入到队列中,队列中再分配相应的执行时间,主线程 runloop 1/60s检测时间,追加的范围为3s-(3+1/60)秒
第二个参数为 NULL:创建的是串行队列
第二个参数为:DISPATCH_QUEUE_CONCURRENT,是并发队列
dispatch_async:创建异步任务,会开启新线程,不会阻塞主线程
dispatch_sync:创建同步任务,不会开启新线程,会阻塞主线程、造成 死锁
dispatch_set_target_queue(“要修改优先级的队列”,“参照物”):修改队列的优先级/通过将多个队列设置到同一个目标队列上,可以让这些队列同步运行
dispatch_barrier_async()和dispatch_barrier_async()都会等他们前面的任务执行完再执行,他们后面的任务会在他们执行完再执行,区别在于 async 后面的任务不会等到其执行完再加入 queue,但是 sync 会
dispatch_group_async:会等组里面的任务都执行完了,再去执行dispatch_group_noticy中的任务
dispatch_semaphore_t:信号量机制,保证线程操作安全,确保一次只有一个在操作共享资源,在操作前调用dispatch_semaphore_wait 申请资源,让计数-1,操作完要调用dispatch_semaphore_signal()释放资源,计数+1
dispatch_once:让block 中代码在应用程序的生命周期里面只执行一次
dispatch_suspend:挂起为执行的 queue,对于已经开始执行的 queue 没有作用
dispatch_resume:让被挂起的 queue 恢复执行
1. libdispatch 会先从 Global Diapatch的自身的 FIFO 队列中取出 dispatch Continuation,
2. 然后调用 pthread_workqueue_additem_np 函数,将该 Global Disapatch 自身以及符合其优先级的workqueue 还有 dispatch Conitunation 的回调函数作为参数传递过去
3. pthread_workqueue_additem_np 使用 wokq_kernreturn 系统调用,通知 workqueue 增加应当执行的项目
4. XNU 内核根据该通知确定要不要生成线程,如果是 Overcommite 优先级的,则始终生成线程(优先级中有Overcommite使用在串行队列中,所以会始终生成线程)
5. workqueue 的线程执行 pthread_workqueue 函数,该函数调用libdispatch的回调函数,在该回调函数中执行加入到dispatch Continuation,的 block
6. block 执行结束后,进行通知 dispatch group 结束,释放dispatch Continuation, 准备下一个 block。
首先先来理解 几个概念
串行和并发;同步与异步
1. 串行和并发
串行:一次只能有一个任务执行并发:在某一时间间隔内,有两个或者两个以上的任务一起执行(本质还是串行的,只不过按照时间片轮转的方式交替执行)。
2. 同步和异步
同步:同步就是任务要等到前面的任务执行完成之后他才可以执行,不会新开辟线程,所以对于一些耗时操作要放到子线程,不然会阻塞主线程异步:不用等待前面的执行完,会新开辟一条线程去执行该任务。
GCD 的 相关概念
GCD 是系统为我们提供的一套 c 语言的 API,不是 Objective-c的对象,是对 NSThread 的封装。1. Serial Dispatch Queue 和Concunrrent Dispatch Queue
*. Serial dispach Queue:串行队列一次只能有一个任务运行
可以生成很多个,创建了多少个串行队列就生成了多少个线程,但是对于系统来说大量的创建串行队列,会浪费内存,引起大量的上下文切换,影响程序的响应性能
*. Concunrrent Dispatch Queue:并发队列
某一时间间隔里可以有多个任务同时运行
并发队列中并发任务的数量是由 XNU 内核的状态决定的
相对于串行队列,不管生成了多少个Concunrrent Dispatch Queue:,系统指挥管理有效的并发队列
当创建了多个并发队列的时候,各个队列之间是并发的。
2. Main Dispatch Queue 和Global Dispatch Queue
这是系统为我们默认提供的*. Main Dispatch Queue:主队列
当程序开始运行时,系统会为我们创建一个主线程,诸葛主队列就在主线程里面,因为主线程只有一个,所以主队列也就只有一个,因此主队列是一个串行队列
被加入到主队列的任务,必须在主 runloop 中执行(runloop 与线程的关系请点这里runloop 与线程的关系)
主队列是由系统默认创建的,可以通过dispatch_get_main_queue()的方式来获取
对于界面的刷新是要放到主队列的.
*. Global Dispatch Queue:全局队列
一个全局队列,所有的应用程序都可以用,是并发的
Global Dispatch Queue:有四个优先级
*. 高优先级
*. 低优先级
*. 默认优先级
*. 后台优先级
由 XNU 内核管理的用于Global Dispatch Queue的的线程会将Global Dispatch Queue的的优先级作为线程的优先级。
GCD的 API
1. dispatch_queue_create(”queue名”,queue 属性)
第一个参数是队列名,第二个参数是队列的属性,返回值是 dispatch_queue_t 类型的当第二个参数是 NULL,创建的是串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("serial dispatch queue", NULL); NSLog(@"%@",serialQueue); //打印结果:<OS_dispatch_queue: serial dispatch queue[0x608000168880]>
当第二个参数是DISPATCH_QUEUE_CONCURRENT,创建的是并发队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent dispatch queue", DISPATCH_QUEUE_CONCURRENT); NSLog(@"%@",concurrentQueue); //打印结果:<OS_dispatch_queue: concurrent dispatch queue[0x600000165580]>
2. dispatch_async:创建异步任务(指定的 queue,要执行的 block 块)
第一个参数是队列(串行还是并发),第二个是我们要执行的任务块会开启一个新的线程,来执行 block 中的内容,要是刷新界面需要切换到主队列
代码如下
NSLog(@"开启一个异步任务%@",[NSThread currentThread]); });
2. dispatch_sync(指定的 queue,要执行的 block 块)
创建同步任务,不会开启新的线程,所以会阻塞主线程会造成死锁(在回调的queue是main queue的前提下)
代码如下
dispatch_sync(Queue, ^{ NSLog(@"开启一个同步任务"); });
3. dispatch_set_target_queue:(Queue1,Queue2)改变队列的优先级
修改队列的优先级dispatch_queue_t test1 = dispatch_queue_create("test1",NULL); dispatch_queue_t test2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0); dispatch_set_target_queue(test1, test2); //第一个是要是修改优先级的 queue,第二个是参照物,将 test1的优先级设置为和 test2一样
应用1:不管是并行队列还是串行队列,当任务以异步的方式被添加到队列中,队列之间是并发的,要想让队列之间同步,可以将要同步的队列的目标队列设置为同一个,如下例子
dispatch_queue_t test1 = dispatch_queue_create("test1 dispatch queue", NULL ); dispatch_queue_t test2 = dispatch_queue_create("test2 dispatch queue1", NULL); dispatch_async(test1, ^{ for (int i = 0; i<5; i++) { NSLog(@"我在test1 %d",i); } }); dispatch_async(test2, ^{ for (int i = 0; i<5; i++) { NSLog(@"我在test2 %d",i); } }); //运行结果如下 2017-02-14 10:48:56.371 AFNetWorkingTestDemo[23510:1106181] 我在test1 0 2017-02-14 10:48:56.371 AFNetWorkingTestDemo[23510:1106181] 我在test1 1 2017-02-14 10:48:56.371 AFNetWorkingTestDemo[23510:1106174] 我在test2 0 2017-02-14 10:48:56.372 AFNetWorkingTestDemo[23510:1106181] 我在test1 2 2017-02-14 10:48:56.372 AFNetWorkingTestDemo[23510:1106181] 我在test1 3 2017-02-14 10:48:56.372 AFNetWorkingTestDemo[23510:1106181] 我在test1 4 2017-02-14 10:48:56.372 AFNetWorkingTestDemo[23510:1106174] 我在test2 1 2017-02-14 10:48:56.372 AFNetWorkingTestDemo[23510:1106174] 我在test2 2 2017-02-14 10:48:56.372 AFNetWorkingTestDemo[23510:1106174] 我在test2 3 2017-02-14 10:48:56.373 AFNetWorkingTestDemo[23510:1106174] 我在test2 4
可以看出两个队列交替打印,所以说队列之间是并发的
修改代码如下
dispatch_queue_t test1 = dispatch_queue_create("test1 dispatch queue", NULL ); dispatch_queue_t test2 = dispatch_queue_create("test2 dispatch queue1", NULL); dispatch_set_target_queue(test2, test1);//加了 该行代码 dispatch_async(test1, ^{ for (int i = 0; i<5; i++) { NSLog(@"我在test1 %d",i); } }); dispatch_async(test2, ^{ for (int i = 0; i<5; i++) { NSLog(@"我在test2 %d",i); } }); //打印结果如下 2017-02-14 10:48:03.311 AFNetWorkingTestDemo[23484:1105222] 我在test1 0 2017-02-14 10:48:03.312 AFNetWorkingTestDemo[23484:1105222] 我在test1 1 2017-02-14 10:48:03.312 AFNetWorkingTestDemo[23484:1105222] 我在test1 2 2017-02-14 10:48:03.313 AFNetWorkingTestDemo[23484:1105222] 我在test1 3 2017-02-14 10:48:03.313 AFNetWorkingTestDemo[23484:1105222] 我在test1 4 2017-02-14 10:48:03.313 AFNetWorkingTestDemo[23484:1105222] 我在test2 0 2017-02-14 10:48:03.314 AFNetWorkingTestDemo[23484:1105222] 我在test2 1 2017-02-14 10:48:03.314 AFNetWorkingTestDemo[23484:1105222] 我在test2 2 2017-02-14 10:48:03.314 AFNetWorkingTestDemo[23484:1105222] 我在test2 3 2017-02-14 10:48:03.315 AFNetWorkingTestDemo[23484:1105222] 我在test2 4
可以看出test2在 test1完成以后 test2才开始执行
应用2:当一个任务被追加到不同的串行队列中,但是串行队列之间是并发的,可以通过设置优先级的方式让其同步执行
4. dispatch_barrier_async和dispatch_barrier_sync
1.比较* 共同点:他之前的任务会在他之前完成,他之后的任务会等他在执行完后执行
* 不同点:dispatch_barrier_async后面的任务不会等他执行完再 被添加进 队列;dispatch_barrier_sync后面的任务会等他再执行完以后再添加 进队列
* 任务是 先添加进队列,但是并不是一添加进去就开始执行
2. 例子
//dispatch_barrier_async dispatch_async(test1, ^{ for (int i = 0; i<5; i++) { NSLog(@"我是任务1"); } }); dispatch_async(test1, ^{ for (int i = 0; i<5; i++) { NSLog(@"我是任务2"); } }); NSLog(@"我在 dispatch_barrier_async之前"); dispatch_barrier_async(test1, ^{//任务0 for (int i = 0; i<5; i++) { NSLog(@"我是任务0"); } }); NSLog(@"我在 dispatch_barrier_async之后");//该行代码会在任务0还没有执行完就会被执行 dispatch_async(test1, ^{ for (int i = 0; i<5; i++) { NSLog(@"我是任务3"); } }); dispatch_async(test1, ^{ for (int i = 0; i<5; i++) { NSLog(@"我是任务4"); } }); //dispatch_barrier_async打印结果如下 2017-02-14 11:15:32.201 AFNetWorkingTestDemo[23777:1118873] 我是任务1 2017-02-14 11:15:32.201 AFNetWorkingTestDemo[23777:1118830] 我在 dispatch_barrier_async之前 2017-02-14 11:15:32.201 AFNetWorkingTestDemo[23777:1118866] 我是任务2 2017-02-14 11:15:32.202 AFNetWorkingTestDemo[23777:1118873] 我是任务1 2017-02-14 11:15:32.202 AFNetWorkingTestDemo[23777:1118830] 我在 dispatch_barrier_async之后 2017-02-14 11:15:32.202 AFNetWorkingTestDemo[23777:1118866] 我是任务2 2017-02-14 11:15:32.202 AFNetWorkingTestDemo[23777:1118873] 我是任务1 2017-02-14 11:15:32.203 AFNetWorkingTestDemo[23777:1118866] 我是任务2 2017-02-14 11:15:32.204 AFNetWorkingTestDemo[23777:1118873] 我是任务1 2017-02-14 11:15:32.204 AFNetWorkingTestDemo[23777:1118866] 我是任务2 2017-02-14 11:15:32.204 AFNetWorkingTestDemo[23777:1118873] 我是任务1 2017-02-14 11:15:32.205 AFNetWorkingTestDemo[23777:1118866] 我是任务2 2017-02-14 11:15:32.205 AFNetWorkingTestDemo[23777:1118866] 我是任务0 2017-02-14 11:15:32.206 AFNetWorkingTestDemo[23777:1118866] 我是任务0 2017-02-14 11:15:32.207 AFNetWorkingTestDemo[23777:1118866] 我是任务0 2017-02-14 11:15:32.208 AFNetWorkingTestDemo[23777:1118866] 我是任务0 2017-02-14 11:15:32.208 AFNetWorkingTestDemo[23777:1118866] 我是任务0 2017-02-14 11:15:32.208 AFNetWorkingTestDemo[23777:1118866] 我是任务3 2017-02-14 11:15:32.208 AFNetWorkingTestDemo[23777:1118873] 我是任务4 2017-02-14 11:15:32.225 AFNetWorkingTestDemo[23777:1118866] 我是任务3 2017-02-14 11:15:32.225 AFNetWorkingTestDemo[23777:1118873] 我是任务4 2017-02-14 11:15:32.247 AFNetWorkingTestDemo[23777:1118866] 我是任务3 2017-02-14 11:15:32.251 AFNetWorkingTestDemo[23777:1118873] 我是任务4 2017-02-14 11:15:32.251 AFNetWorkingTestDemo[23777:1118866] 我是任务3 2017-02-14 11:15:32.252 AFNetWorkingTestDemo[23777:1118873] 我是任务4 2017-02-14 11:15:32.252 AFNetWorkingTestDemo[23777:1118866] 我是任务3 2017-02-14 11:15:32.254 AFNetWorkingTestDemo[23777:1118873] 我是任务4 //dispatch_barrier_sync //**如果把代码中的dispatch_barrier_async变成dispatch_barrier_sync 打印结果如下** 2017-02-14 11:29:22.922 AFNetWorkingTestDemo[23893:1123891] 我是任务1 2017-02-14 11:29:22.922 AFNetWorkingTestDemo[23893:1123881] 我是任务2 2017-02-14 11:29:22.922 AFNetWorkingTestDemo[23893:1123891] 我是任务1 2017-02-14 11:29:22.923 AFNetWorkingTestDemo[23893:1123891] 我是任务1 2017-02-14 11:29:22.923 AFNetWorkingTestDemo[23893:1123891] 我是任务1 2017-02-14 11:29:22.923 AFNetWorkingTestDemo[23893:1123891] 我是任务1 2017-02-14 11:29:22.923 AFNetWorkingTestDemo[23893:1123881] 我是任务2 2017-02-14 11:29:22.922 AFNetWorkingTestDemo[23893:1123797] 我在 dispatch_barrier_sync之前 2017-02-14 11:29:22.924 AFNetWorkingTestDemo[23893:1123881] 我是任务2 2017-02-14 11:29:22.925 AFNetWorkingTestDemo[23893:1123881] 我是任务2 2017-02-14 11:29:22.925 AFNetWorkingTestDemo[23893:1123881] 我是任务2 2017-02-14 11:29:22.926 AFNetWorkingTestDemo[23893:1123797] 我是任务0 2017-02-14 11:29:22.926 AFNetWorkingTestDemo[23893:1123797] 我是任务0 2017-02-14 11:29:22.927 AFNetWorkingTestDemo[23893:1123797] 我是任务0 2017-02-14 11:29:22.927 AFNetWorkingTestDemo[23893:1123797] 我是任务0 2017-02-14 11:29:22.928 AFNetWorkingTestDemo[23893:1123797] 我是任务0 2017-02-14 11:29:22.928 AFNetWorkingTestDemo[23893:1123797] 我在 dispatch_barrier_sync之后//会在任务0执行完再打印 2017-02-14 11:29:22.929 AFNetWorkingTestDemo[23893:1123891] 我是任务4 2017-02-14 11:29:22.929 AFNetWorkingTestDemo[23893:1123891] 我是任务4 2017-02-14 11:29:22.929 AFNetWorkingTestDemo[23893:1123881] 我是任务3 2017-02-14 11:29:22.930 AFNetWorkingTestDemo[23893:1123891] 我是任务4 2017-02-14 11:29:22.930 AFNetWorkingTestDemo[23893:1123891] 我是任务4 2017-02-14 11:29:22.930 AFNetWorkingTestDemo[23893:1123891] 我是任务4 2017-02-14 11:29:22.930 AFNetWorkingTestDemo[23893:1123881] 我是任务3 2017-02-14 11:29:22.931 AFNetWorkingTestDemo[23893:1123881] 我是任务3 2017-02-14 11:29:22.932 AFNetWorkingTestDemo[23893:1123881] 我是任务3 2017-02-14 11:29:22.932 AFNetWorkingTestDemo[23893:1123881] 我是任务3
从上面的例子中可以看出这两个的区别:其实不难理解,因为 async 是一部的,所以不会阻塞线程,但是 sync 会阻塞线程,所以同步和异步的区别是在这里体现的
5. dispatch_group_async(group ,queue,block)
会等添加进 group 中的所有任务执行完再执行 dispatch_group_notify的任务,如果我们想要任务3在任务1和2执行完后再执行,就把1和2放到同一个组里,例子如下dispatch_group_t group = dispatch_group_create();//创建一个组 //将任务1加入 group 中 dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务1-1"); [NSThread sleepForTimeInterval:3]; NSLog(@"任务1-2"); }); //将任务2加入 group 中 dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务2-1"); [NSThread sleepForTimeInterval:3]; NSLog(@"任务2-2"); }); dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{ NSLog(@"任务3-1"); [NSThread sleepForTimeInterval:3]; NSLog(@"任务3-2"); }); //结果如下 2017-02-14 11:44:49.912 AFNetWorkingTestDemo[24094:1132147] 任务1-1 2017-02-14 11:44:49.912 AFNetWorkingTestDemo[24094:1132138] 任务2-1 2017-02-14 11:44:52.912 AFNetWorkingTestDemo[24094:1132147] 任务1-2 2017-02-14 11:44:52.912 AFNetWorkingTestDemo[24094:1132138] 任务2-2 2017-02-14 11:44:52.914 AFNetWorkingTestDemo[24094:1132138] 任务3-1//任务3等到任务1和2执行完再执行 2017-02-14 11:44:55.916 AFNetWorkingTestDemo[24094:1132138] 任务3-2
dispatch_group_async和dispatch_barrier_async 对比
都会在其前面的任务完成之后再执行
但是dispatch_barrier_async得后面的任务是在他执行完后再执行
dispatch_group_async中没有加入组中的任务是在所有组中的任务完成以后再执行
dispatch_group_wait和 dispatch_group_noticy
dispatch_group_wait可以指定在 group 的任务再执行了几秒时候做某些反应
//第一个参数,开始时间、第二个参数当 group 中的任务执行多少面开始做某些事情,要是设置为DISPATCH_TIME_FOREVER,则会等 group 中的处理完再做,返回值为0,说明处理完,不为0,说明没处理完 dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW,DISPATCH_TIME_FOREVER); long result = dispatch_group_wait(group, timeout); >
dispatch_group_noticy在 group 中的处理完再做
6:dispatch_semaphore_t:信号量机制
要进行操作前会判断semaphore的计数是不是大于等于1,是的话先让信号量计数-1,然后执行操作,操作执行完成后,再让信号量+1dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//设置信号量初始值为1 NSMutableArray *array = [NSMutableArray array]; for (int i = 0; i<5; i++) { //之要信号量值不大于等于1,就会一直等待,知道>=1,再对数组进行操作. dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [array addObject:[NSString stringWithFormat:@"%d",i]]; //对数组进行完操作,让信号量计数+1,这样下次有线程要访问,就可以访问 dispatch_semaphore_signal(semaphore); }
相当于操作系统中的 wait-sigal 操作,那个数组就是一个共享资源,只要有人在用(当 信号量计数为1),别的就会陷入等待,直到别人不用了,再去用,用之前先让计数-1,这样当别的人来用,就会知道有人在用,我还是等待吧,用完后,要记得让计数+1,释放这个资源,告诉别人这个资源我已经不用了,你可以用了**因为####7. dispatch_apply:让代码重复执行
//第一个参数是重复执行的次数, //第二个参数是一个队列, //第三个参数是下标,用来区分不同的 block dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) { NSLog(@"%d",index); });
应用:可以利用他来遍历数组
8. dispatch_once;
让代码在应用程序的生命周期中只执行一次可以用来实现单例,线程安全
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ }); >
9. dispatch_suspend(Queue)和 dispatch_resume(Queue);
dispatch_suspend挂起一个尚未执行的 queue:如果这个 queue 已经在执行,没有影响,要是没有执行就停止执行dispatch_resume让被挂起的 queue 继续执行。
10. dispatch_after()
延迟一段时间执行不是一定时间后执行相应的任务,而是在一定时间后将其加入到队列中,队列中再分配相应的执行时间,主线程 runloop 1/60s检测时间,追加的范围为3s-(3+1/60)秒
总结
dispatch_queue_create(“queue 名字”,queue的属性);第二个参数为 NULL:创建的是串行队列
第二个参数为:DISPATCH_QUEUE_CONCURRENT,是并发队列
dispatch_async:创建异步任务,会开启新线程,不会阻塞主线程
dispatch_sync:创建同步任务,不会开启新线程,会阻塞主线程、造成 死锁
dispatch_set_target_queue(“要修改优先级的队列”,“参照物”):修改队列的优先级/通过将多个队列设置到同一个目标队列上,可以让这些队列同步运行
dispatch_barrier_async()和dispatch_barrier_async()都会等他们前面的任务执行完再执行,他们后面的任务会在他们执行完再执行,区别在于 async 后面的任务不会等到其执行完再加入 queue,但是 sync 会
dispatch_group_async:会等组里面的任务都执行完了,再去执行dispatch_group_noticy中的任务
dispatch_semaphore_t:信号量机制,保证线程操作安全,确保一次只有一个在操作共享资源,在操作前调用dispatch_semaphore_wait 申请资源,让计数-1,操作完要调用dispatch_semaphore_signal()释放资源,计数+1
dispatch_once:让block 中代码在应用程序的生命周期里面只执行一次
dispatch_suspend:挂起为执行的 queue,对于已经开始执行的 queue 没有作用
dispatch_resume:让被挂起的 queue 恢复执行
Block 如何被添加进 Dispatch queue 中
block 并不是直接被添加进 Queue 中的,而是会先被添加进一个 Dispatch Continuation 的结构体中,这个结构体用于保存 block 所属的 group 以及其它一些信息。block在 Queue 中如何执行
当 Global Diapatch Queue 开始执行 block 时,1. libdispatch 会先从 Global Diapatch的自身的 FIFO 队列中取出 dispatch Continuation,
2. 然后调用 pthread_workqueue_additem_np 函数,将该 Global Disapatch 自身以及符合其优先级的workqueue 还有 dispatch Conitunation 的回调函数作为参数传递过去
3. pthread_workqueue_additem_np 使用 wokq_kernreturn 系统调用,通知 workqueue 增加应当执行的项目
4. XNU 内核根据该通知确定要不要生成线程,如果是 Overcommite 优先级的,则始终生成线程(优先级中有Overcommite使用在串行队列中,所以会始终生成线程)
5. workqueue 的线程执行 pthread_workqueue 函数,该函数调用libdispatch的回调函数,在该回调函数中执行加入到dispatch Continuation,的 block
6. block 执行结束后,进行通知 dispatch group 结束,释放dispatch Continuation, 准备下一个 block。
相关文章推荐
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- iphone ios 如何使用gcd,block
- IOS开发(61)之GCD执行非UI的操作
- ios开发如何给程序添加icon图标
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法 推荐
- Flash开发iOS应用全攻略(三)——如何使用iOS开发者授权以及如何申请证书
- iphone ios 如何使用gcd,block
- iOS如何添加图片资源以及设置应用程序图标
- IOS开发(60)之使用GCD执行UI操作
- 【iOS-Cocos2d游戏开发之十六】添加本地通知(UILocalNotification)以及添加系统组件滚动视图(UIScrollView)!【2011年11月15日更新】
- ios开发笔记:如何在iphone/ipad应用程序添加iAd
- Flash开发iOS应用全攻略(三)——如何使用iOS开发者授权以及如何申请证书
- iOS如何添加图片资源以及设置应用程序图标
- Ubuntu下经典JAVA开发环境搭建 以及 Ubuntu中如何在桌面、启动面板以及应用程序菜单上添加图标
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- 【iOS-Cocos2d游戏开发之十一】使用Box2d物理系统以及在cocos2d框架添加Box2d物理系统lib包的方法
- iOS线程开发之--BLOCK & GCD(Grand Central Dispatch)
- ios 如何使用gcd,block
- iphone ios 如何使用gcd,block