OC多线程之GCD ----- 2
dispatch_create生成的Queue不管是并行队列还是串行队列,其优先级都是默认优先级
但是可以用dispatch_set_target_queue来改变队列的优先级
dispatch_set_target_queue(原来的队列, 目标优先级队列)
使用这个函数需要获取两个队列,一个是需要变更优先级的队列,一个是指定优先级的队列(指定优先级的队列可以通过get_global获得)
如果多个串行队列优先级相同,那么这些队列里的任务也会串行执行
dispatch_after函数并不能非常精确的在一段时间后执行任务,dispatch_after只是在指定时间后将block插入到队列中,至于什么时候执行要看系统的执行状况
延迟多少触发大家都知道,下面这个代码是利用NSDate生成一个时间,让dispatch在这个时间去执行block,但是这个貌似只能精确到分,没有精确到秒,可能是我代码有问题,原因还早查找中
@implementation NSDate (dis) -(dispatch_time_t)getDis{ NSTimeInterval interval; double second,subsecond; struct timespec time; dispatch_time_t milestone; interval = [self timeIntervalSince1970]; subsecond = modf(interval, &second); time.tv_sec = second; time.tv_nsec = subsecond * NSEC_PER_SEC; milestone = dispatch_walltime(&time, 0); return milestone; } @end
GCD使用过程中应该谨慎使用sync函数,因为稍有不慎就将导致死锁
dispatch_apply函数是asyn和group的关联API,该函数可以执行指定次数的block 但是会阻塞线程(同步执行),见下面的代码
dispatch_apply(10, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) { NSLog(@"%zu",index); }); NSLog(@"done");
//===============打印结果
2014-06-19 20:58:55.097 efvervq[5840:60b] 0
2014-06-19 20:58:55.097 efvervq[5840:1303] 1
2014-06-19 20:58:55.097 efvervq[5840:3803] 2
2014-06-19 20:58:55.099 efvervq[5840:60b] 4
2014-06-19 20:58:55.097 efvervq[5840:3903] 3
2014-06-19 20:58:55.099 efvervq[5840:1303] 5
2014-06-19 20:58:55.099 efvervq[5840:3803] 6
2014-06-19 20:58:55.099 efvervq[5840:60b] 7
2014-06-19 20:58:55.101 efvervq[5840:3803] 9
2014-06-19 20:58:55.099 efvervq[5840:3903] 8
2014-06-19 20:58:55.102 efvervq[5840:60b] done
//=================
顺序不一,但是在函数外面的done是最后打印的
PS.但是不要搞混了.使用并行队列和sync函数连续添加block时打印出来的书序是0123456789的
我们可以在async函数中使用apply函数,这样能避免阻塞主队列
dispatch_suspend(queue)可以将队列挂起,
dispatch_resume(queue)可以恢复指定的queue,然后系统会继续执行未处理的操作,对已经执行的没有影响
有时需要十分精准的数据安全控制,那么使用dispatch_semaphore可以提供比SerialQueue更加细小颗粒度的访问控制,因为这个是通过信号量控制的
但信号量<0时时不允许访问的
看下面的代码
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); /** * 生成dispatch_semaphore * 将其计数初始值设为1 * 保证可访问NSMutableArray类对象的线程同时只能有一个 */ dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); NSMutableArray *array = [NSMutableArray array]; for (int i = 0; i < 10000; i++) { dispatch_async(queue, ^{ /** * 等待 dispatch_semaphore * * 一直等待,知道semaphore数值大于等于1 */ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); /** * 执行到此,信号量为1 然后系统自动减去1,变为0 * 此时只有执行到这的线程访问array */ [array addObject:[NSNumber numberWithInt:i]]; /** * 访问结束后,给信号量+1.以便其他的线程继续像array中添加对象 */ dispatch_semaphore_signal(semaphore); }); }
GCD除了队列之外还有dispatch_source,这个功能可以以相当低的资源消耗来处理文件读写,定时器,信号接收等事件,更多功能可以去查阅苹果的文档
/** * 创建一个source DISPATCH_SOURCE_TYPE_TIMER 为source的类型(定时器) */ dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue()); /** * 设置时间 * 延迟15秒后 * 每2秒重复一次 *允许延迟1秒 */ dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 15ull * NSEC_PER_SEC), 2ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC); // 执行的任务 __block int a = 0; dispatch_source_set_event_handler(timer, ^{ NSLog(@"wake up"); a++; if (a == 8) { dispatch_source_cancel(timer); } }); //取消时的操作 dispatch_source_set_cancel_handler(timer, ^{ NSLog(@"cancled"); }); /** * 如果是MRC 需要dispatch_release */ //开始工作 dispatch_resume(timer);
如果你想不让timer重复执行,可以将重复时间设为dispatch_timeForever 或者在set_event_handler里面执行完毕以后cancle掉
set_event_handler里面必须有cancel(或者里面执行的方法有cancel,就是可以搜寻到),否则timer不会执行,你可以自己试试
但是你可以用if(0){cancel}来骗过系统,但是一定不要忘记cancel