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

 

posted @ 2014-08-10 22:31  784692237  阅读(481)  评论(0编辑  收藏  举报