ios gcd学习

ios中的多线程,除了可以用NSThread,还可以使用gcd。gcd的功能还是十分强大的,下面来详细了解一下。gcd是系统一个提供的一个线程队列,当我们需要使用多线程时,只要向已知的队列中添加任务。队列就会按照一定机制去执行这些任务。

队列分3类分别是:

        连续队列: 顺序执行任务

        并发队列:并发执行一个或者多个任务

        主队列:它是应用程序中有效队列的主队列,执行的是应用程序中的主线程任务

        首先看连续队列

        

dispatch_queue_t my_serial_queue;

    my_serial_queue = dispatch_queue_create("com.apress.MySerialQueue1", NULL);

    dispatch_block_t myBlock1=^{

        NSLog(@"My block1 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];

        NSLog(@"My block1 end");

    };

    dispatch_block_t myBlock2=^{

        NSLog(@"My block2 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:4.0]];

        NSLog(@"My block2 end");

    };

    dispatch_block_t myBlock3=^{

        NSLog(@"My block3 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];

        NSLog(@"My block3 end");

    };

    dispatch_block_t myBlock4=^{

        NSLog(@"My block4 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

        NSLog(@"My block4 end");

    };

    dispatch_block_t myBlock5=^{

        NSLog(@"My block5 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];

        NSLog(@"My block5 end");

    };

    

    NSLog(@"sync add start==================");

    dispatch_sync(my_serial_queue, myBlock1);

    NSLog(@"sync add my block1");

    dispatch_sync(my_serial_queue, myBlock2);

    NSLog(@"sync add my block2");

    dispatch_sync(my_serial_queue, myBlock3);

    NSLog(@"sync add my block3");

    dispatch_sync(my_serial_queue, myBlock4);

    NSLog(@"sync add my block4");

    dispatch_sync(my_serial_queue, myBlock5);

    NSLog(@"add my block5");

    NSLog(@"sync add end==================");

    

    

    NSLog(@"async add start==================");

    dispatch_async(my_serial_queue, myBlock1);

    NSLog(@"async add my block1");

    dispatch_async(my_serial_queue, myBlock2);

    NSLog(@"async add my block2");

    dispatch_async(my_serial_queue, myBlock3);

    NSLog(@"async add my block3");

    dispatch_async(my_serial_queue, myBlock4);

    NSLog(@"async add my block4");

    dispatch_async(my_serial_queue, myBlock5);

    NSLog(@"asyncadd my block5");

    NSLog(@"async add end==================");

首先创建了一个连续队列

my_serial_queue = dispatch_queue_create("com.apress.MySerialQueue1",NULL);

第一个参数传入队列的名称,第二个是队列的属性,这里传入NULL

之后分别使用同步(dispatch_sync)和异步(dispatch_sync)添加任务,运行后的log如下:

2018-05-14 17:42:34.348926+0800 ocLearner[50012:1981077] sync add start==================

2018-05-14 17:42:34.349117+0800 ocLearner[50012:1981077] My block1 start

2018-05-14 17:42:39.352441+0800 ocLearner[50012:1981077] My block1 end

2018-05-14 17:42:39.352760+0800 ocLearner[50012:1981077] sync add my block1

2018-05-14 17:42:39.352935+0800 ocLearner[50012:1981077] My block2 start

2018-05-14 17:42:43.353401+0800 ocLearner[50012:1981077] My block2 end

2018-05-14 17:42:43.353689+0800 ocLearner[50012:1981077] sync add my block2

2018-05-14 17:42:43.353876+0800 ocLearner[50012:1981077] My block3 start

2018-05-14 17:42:46.355402+0800 ocLearner[50012:1981077] My block3 end

2018-05-14 17:42:46.355735+0800 ocLearner[50012:1981077] sync add my block3

2018-05-14 17:42:46.355946+0800 ocLearner[50012:1981077] My block4 start

2018-05-14 17:42:48.357490+0800 ocLearner[50012:1981077] My block4 end

2018-05-14 17:42:48.357802+0800 ocLearner[50012:1981077] sync add my block4

2018-05-14 17:42:48.357998+0800 ocLearner[50012:1981077] My block5 start

2018-05-14 17:42:49.358719+0800 ocLearner[50012:1981077] My block5 end

2018-05-14 17:42:49.359042+0800 ocLearner[50012:1981077] add my block5

2018-05-14 17:42:49.359220+0800 ocLearner[50012:1981077] sync add end==================

2018-05-14 17:42:49.359423+0800 ocLearner[50012:1981077] async add start==================

2018-05-14 17:42:49.359680+0800 ocLearner[50012:1981077] async add my block1

2018-05-14 17:42:49.359720+0800 ocLearner[50012:1981348] My block1 start

2018-05-14 17:42:49.359940+0800 ocLearner[50012:1981077] async add my block2

2018-05-14 17:42:49.360112+0800 ocLearner[50012:1981077] async add my block3

2018-05-14 17:42:49.360338+0800 ocLearner[50012:1981077] async add my block4

2018-05-14 17:42:49.360533+0800 ocLearner[50012:1981077] asyncadd my block5

2018-05-14 17:42:49.360913+0800 ocLearner[50012:1981077] async add end==================

2018-05-14 17:42:54.365384+0800 ocLearner[50012:1981348] My block1 end

2018-05-14 17:42:54.365683+0800 ocLearner[50012:1981348] My block2 start

2018-05-14 17:42:58.366416+0800 ocLearner[50012:1981348] My block2 end

2018-05-14 17:42:58.367190+0800 ocLearner[50012:1981348] My block3 start

2018-05-14 17:43:01.372527+0800 ocLearner[50012:1981348] My block3 end

2018-05-14 17:43:01.372879+0800 ocLearner[50012:1981348] My block4 start

2018-05-14 17:43:03.374228+0800 ocLearner[50012:1981348] My block4 end

2018-05-14 17:43:03.374553+0800 ocLearner[50012:1981348] My block5 start

2018-05-14 17:43:04.376980+0800 ocLearner[50012:1981348] My block5 end

可以看出,同步添加方法会等方法执行完成以后才返回,异步添加方法会直接返回,不需要等待任务是否完成。

那么如果是并发队列呢,来看代码

dispatch_queue_t my_queue;

    my_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_block_t myBlock1=^{

        NSLog(@"My block1 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:5.0]];

        NSLog(@"My block1 end");

    };

    dispatch_block_t myBlock2=^{

        NSLog(@"My block2 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:4.0]];

        NSLog(@"My block2 end");

    };

    dispatch_block_t myBlock3=^{

        NSLog(@"My block3 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];

        NSLog(@"My block3 end");

    };

    dispatch_block_t myBlock4=^{

        NSLog(@"My block4 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

        NSLog(@"My block4 end");

    };

    dispatch_block_t myBlock5=^{

        NSLog(@"My block5 start");

        [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];

        NSLog(@"My block5 end");

        

    };

    NSLog(@"sync add start==================");

    dispatch_sync(my_queue, myBlock1);

    NSLog(@"sync add my block1");

    dispatch_sync(my_queue, myBlock2);

    NSLog(@"sync add my block2");

    dispatch_sync(my_queue, myBlock3);

    NSLog(@"sync add my block3");

    dispatch_sync(my_queue, myBlock4);

    NSLog(@"sync add my block4");

    dispatch_sync(my_queue, myBlock5);

    NSLog(@"sync add my block5");

    NSLog(@"sync add end==================");

    

    NSLog(@"async add start==================");

    dispatch_async(my_queue, myBlock1);

    NSLog(@"async add my block1");

    dispatch_async(my_queue, myBlock2);

    NSLog(@"async add my block2");

    dispatch_async(my_queue, myBlock3);

    NSLog(@"async add my block3");

    dispatch_async(my_queue, myBlock4);

    NSLog(@"async add my block4");

    dispatch_async(my_queue, myBlock5);

    NSLog(@"async add my block5");

    NSLog(@"async add end==================");

首先看并发队列的创建

dispatch_queue_t my_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

第一个参数代表优先级,除了默认优先级外,还有DISPATCH_QUEUE_PRIORITY_HIGH和DISPATCH_QUEUE_PRIORITY_LOW两个优先级。第二个参数都填0

和顺序队列的测试一样,也是分别用同步添加和异步添加的方法向队列添加任务,来看一下执行后的log

2018-05-15 10:08:41.423023+0800 ocLearner[50946:2026857] sync add start==================

2018-05-15 10:08:41.430928+0800 ocLearner[50946:2026857] My block1 start

2018-05-15 10:08:46.431787+0800 ocLearner[50946:2026857] My block1 end

2018-05-15 10:08:46.432072+0800 ocLearner[50946:2026857] sync add my block1

2018-05-15 10:08:46.432252+0800 ocLearner[50946:2026857] My block2 start

2018-05-15 10:08:50.433081+0800 ocLearner[50946:2026857] My block2 end

2018-05-15 10:08:50.433401+0800 ocLearner[50946:2026857] sync add my block2

2018-05-15 10:08:50.442155+0800 ocLearner[50946:2026857] My block3 start

2018-05-15 10:08:53.443781+0800 ocLearner[50946:2026857] My block3 end

2018-05-15 10:08:53.444092+0800 ocLearner[50946:2026857] sync add my block3

2018-05-15 10:08:53.444310+0800 ocLearner[50946:2026857] My block4 start

2018-05-15 10:08:55.445791+0800 ocLearner[50946:2026857] My block4 end

2018-05-15 10:08:55.446096+0800 ocLearner[50946:2026857] sync add my block4

2018-05-15 10:08:55.446321+0800 ocLearner[50946:2026857] My block5 start

2018-05-15 10:08:56.447314+0800 ocLearner[50946:2026857] My block5 end

2018-05-15 10:08:56.447538+0800 ocLearner[50946:2026857] sync add my block5

2018-05-15 10:08:56.447660+0800 ocLearner[50946:2026857] sync add end==================

2018-05-15 10:08:56.447759+0800 ocLearner[50946:2026857] async add start==================

2018-05-15 10:08:56.447870+0800 ocLearner[50946:2026857] async add my block1

2018-05-15 10:08:56.447884+0800 ocLearner[50946:2027008] My block1 start

2018-05-15 10:08:56.448008+0800 ocLearner[50946:2026857] async add my block2

2018-05-15 10:08:56.448053+0800 ocLearner[50946:2029055] My block2 start

2018-05-15 10:08:56.448167+0800 ocLearner[50946:2026857] async add my block3

2018-05-15 10:08:56.448201+0800 ocLearner[50946:2029056] My block3 start

2018-05-15 10:08:56.448348+0800 ocLearner[50946:2026857] async add my block4

2018-05-15 10:08:56.448381+0800 ocLearner[50946:2029057] My block4 start

2018-05-15 10:08:56.448775+0800 ocLearner[50946:2026857] async add my block5

2018-05-15 10:08:56.449061+0800 ocLearner[50946:2029058] My block5 start

2018-05-15 10:08:56.449233+0800 ocLearner[50946:2026857] async add end==================

2018-05-15 10:08:57.453500+0800 ocLearner[50946:2029058] My block5 end

2018-05-15 10:08:58.454006+0800 ocLearner[50946:2029057] My block4 end

2018-05-15 10:08:59.448899+0800 ocLearner[50946:2029056] My block3 end

2018-05-15 10:09:00.451476+0800 ocLearner[50946:2029055] My block2 end

2018-05-15 10:09:01.451462+0800 ocLearner[50946:2027008] My block1 end


 可以看出,并发的队列,如果是同步添加,并没有实现并发,原因是如果是同步添加,必须等到添加的任务返回后才能继续往下执行。而如果是异步添加,异步队列,可以看出真正实现了并发运行。

第三个队列就是主队列,当我们需要必须在主线程下执行任务时,可以使用主队列,比如更新UI,代码如下:

dispatch_queue_t main_queue = dispatch_get_main_queue();

    dispatch_block_t block1=^{

        UILabel* label = [[UILabel alloc]init];

        label.text=@"dispatch_main_queue";

        label.textColor=UIColor.whiteColor;

        label.frame=CGRectMake(50, 100, 150, 100);

        [self.view addSubview:label];

    };

    dispatch_async(main_queue, block1);

正常情况下如果异步下载完资源,需要用主队列更新。这里为了简化,没有网络下载。仅仅演示了主队列的使用。

还有一个方法dispatch_get_current_queue方法可以获取当前的队列,但是这个方法已经被苹果废弃,因为有可能产生死锁。

下面来延时一下死锁的情况,上代码:

void deadfunc(dispatch_queue_t queue,dispatch_block_t block){

    if(dispatch_get_current_queue() == queue){

        NSLog(@"block");

        block();

    }else{

        NSLog(@"dispatch block");

        dispatch_sync(queue, block);

    }

}


-(void)deadLockFunc{

    dispatch_queue_t queueA = dispatch_queue_create("com.xiaoxiao.queueA", NULL);

    dispatch_queue_t queueB = dispatch_queue_create("com.xiaoxiao.queueB", NULL);

    dispatch_sync(queueA, ^{

        dispatch_sync(queueB, ^{

            dispatch_block_t block = ^{

                NSLog(@"因为产生死锁,这句话用于得不到执行");

            };

            deadfunc(queueA,block);

        });

    });

}


可以看到当代码运行到dispatch_sysc(queue,block);以后将产生死锁,因为这段代码向queueA中同步添加了一个任务,儿代码段本身有在queueA的让一个任务中,所以,新添加的任务用于没有机会执行,因为现在任务需要等待先添加的任务结束才能继续往下运行。

如果想替代dispatch_get_current_queue,可以使用dispatch_queue_set_specific,但是其实个人觉得,这个方法如果使用不当,同样会死锁。因此,要特别关注同步添加的顺序队列的情况。好了,下面仅仅演示dispatch_queue_set_specific

-(void)specificFunc{

    dispatch_queue_t queueA = dispatch_queue_create("com.xiaoxiao.queueA", NULL);

    //dispatch_queue_t queueB = dispatch_queue_create("com.xiaoxiao.queueB", NULL);

    //dispatch_set_target_queue(queueB, queueA);

    static int specificKey;

    CFStringRef specificValue = CFSTR("queueA");

    dispatch_queue_set_specific(queueA,&specificKey,(void*)specificValue,(dispatch_function_t)CFRelease);

    

    

        dispatch_sync(queueA, ^{

            dispatch_block_t block = ^{

                

            };

            CFStringRef retrievedValue = dispatch_get_specific(&specificKey);

            if (retrievedValue) {

                NSLog(@"block");

                block();

            } else {

                NSLog(@"dispatch block");

                dispatch_sync(queueA, block);

            }

        });

}


其实就是给队列添加了一个标记。在需要的时候可以判断是否是特定的队列。

最后再说以队列的上下文吧,因为有些情况下需要传入参数。

传入上下文的方法是:

dispatch_set_context(dispatch_object_t object,void *_Nullable context)

第一个参数是队列对象,第二个参数是C格式的void* 类型指针

下面分别给出上下文是C格式数据和OC格式数据的例子:

typedef struct _Data{

    int number;

} Data;


void cleanStaff(void* context){

    NSLog(@"In clean ,context number:%d",((Data*)context)->number);

    free(context);

}

/**

 传入C数据的上下文

 */

-(void)testBody1{

    dispatch_queue_t queue = dispatch_queue_create("com.xiaoxiao.queue1", NULL);

    Data *myData = malloc(sizeof(Data));

    myData->number=10;

    dispatch_set_context(queue, myData);

    dispatch_set_finalizer_f(queue, cleanStaff);

    

    dispatch_async(queue,^{

        Data *data = dispatch_get_context(queue);

        NSLog(@"1:context number:%d",data->number);

        data->number = 20;

    });

}


void myFinalizerFunction(void *context){

    NSLog(@"myFinallizerFunction");

    NSMutableDictionary *theData = (__bridge_transfer NSMutableDictionary*)context;

    [theData removeAllObjects];

}

可以看到,dispatch_set_context可以设置上下文,dispatch_get_context可以获得之前设置的上下文。另外可以通过dispatch_set_finalizer_f来设置清理函数,当队列销毁的时候,也会调用注册的销毁函数来销毁上下文。

如果上下文是OC对象的化:

void myFinalizerFunction(void *context){

    NSLog(@"myFinallizerFunction");

    NSMutableDictionary *theData = (__bridge_transfer NSMutableDictionary*)context;

    [theData removeAllObjects];

}


-(void)testBody2{

    dispatch_queue_t queue = dispatch_queue_create("com.xiaoxiao.queue2", NULL);

    NSMutableDictionary *myContext =  [[NSMutableDictionary alloc]initWithCapacity:5];

    [myContext setObject:@"My context" forKey:@"title"];

    [myContext setObject:[NSNumber numberWithInt:0] forKey:@"value"];

    dispatch_set_context(queue, (__bridge_retained void*)myContext);

    dispatch_set_finalizer_f(queue,myFinalizerFunction);

    dispatch_async(queue, ^{

        NSMutableDictionary *myContext = (__bridge NSMutableDictionary*)dispatch_get_context(queue);

        NSString* title = [myContext objectForKey:@"title"];

        NSNumber* value = [myContext objectForKey:@"value"];

        NSLog(@"title:%@,value:%d",title,[value intValue]);

    });

}

如果上下文是oc对象,可以看到,在dispatch_set_context的时候需要用__bridge_retained,表示移交了内存管理权,相当于对void* 对象retained了,__bridge_transfer表示c对象释放管理权,把内存控制交给ARC系统。

好了,上下文系统就这些。先写到这里吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值