您的位置:首页 > 移动开发 > IOS开发

iOS多线程开发——GCD的使用与多线程开发浅析

2016-04-29 18:22 507 查看
我在前面的博客中《GCD实践——串行队列/并发队列与IOS多线程详解》中对iOS中的同步异步、串行并行做了较为详细的讲解。在之后的几篇GCD实践的博客中对GCD的使用也有较为详细的实现。但是我们要注意的是,那里用到的GCD是别人对苹果的原生GCD接口封装后的使用,虽然用起来更为方便,但是为了有全面的学习,我还是推荐去用苹果原生的GCD。该案例代码上传至 https://github.com/chenyufeng1991/MoreGCD 。代码中已经有部分注释对理解代码很有帮助。下面我来一一进行讲解。

只要是同步执行的任务,都会在当前线程执行,不会另开线程。只要是异步任务执行的任务,都会另开线程,在别的线程执行。同步操作会阻塞当前线程,直到block中的任务执行完毕,然后当前线程才会继续往下执行。(block在主线程中执行)异步操作,当前线程会直接往下执行,不会阻塞当前线程。 (因为block在新线程中执行)
串行队列:一次只执行一个线程。并行队列:一次可以执行多个线程。

(1)自己创建一个并发队列,并同步执行

//dispatch_queue_t 也可以自己定义,如果要自定义,可以用dispatch_queue_create方法。
//当然也可以使用系统提供的global_queue,main_queue
dispatch_queue_t syncQueue = dispatch_queue_create("my.concurrent.syncQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_sync(syncQueue, ^{
NSLog(@"2");

[NSThread sleepForTimeInterval:3];
NSLog(@"3");
});

NSLog(@"4");
dispatch_release(syncQueue);//最好需要释放
建议该队列使用完后,进行release。

(2)自己创建一个并发队列,异步执行

dispatch_queue_t asyncQueue = dispatch_queue_create("my.concurrent.asyncQueue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(asyncQueue, ^{
NSLog(@"2");

[NSThread sleepForTimeInterval:3];
NSLog(@"3");
});
NSLog(@"4");
dispatch_release(asyncQueue);


(3)自己创建一个串行队列,同步执行

dispatch_queue_t syncQueue = dispatch_queue_create("my.serial.syncQueue", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
dispatch_sync(syncQueue, ^{
NSLog(@"2");

[NSThread sleepForTimeInterval:3];
NSLog(@"3");
});
NSLog(@"4");
dispatch_release(syncQueue);


(4)自己创建一个串行队列,异步执行

dispatch_queue_t asyncQueue = dispatch_queue_create("my.serial.asyncQueue", DISPATCH_QUEUE_SERIAL);
NSLog(@"1");
//第一个参数是指定了一个GCD队列,第二个参数是分配事务到该队列。
dispatch_async(asyncQueue, ^{
NSLog(@"2");

[NSThread sleepForTimeInterval:3];
NSLog(@"3");
});
NSLog(@"4");
dispatch_release(asyncQueue);


(5)关于系统提供的线程
dispatch_global_queue :并行队列
dispatch_private_queue:串行队列
dispatch_main_queue:主线程

以下代码是异步执行耗时操作,并更新UI的代码:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
//进入另一个线程,处理耗时的代码块

dispatch_async(dispatch_get_main_queue(), ^{
//返回主线程刷新

});
});


(6)一次性执行某个操作,并在应用生命周期内仅执行一次

//在该应用声明周期内,下面的代码只会被执行一次。并且是线程安全的。
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"仅会被执行一次");
});


(7)线程组,是一种同步机制,可以让某些线程先执行,某些线程最后执行,以控制线程的执行顺序。

//GCD的高级用法 线程组;线程组和信号量机制都可以实现队列的同步。
__block int i;
__block int j;
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
i = 1;
});

dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
j = 2;
});

dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
NSLog(@"%d",i+j);
});

(8)线程的延迟执行

NSLog(@"1");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"延迟3s执行这里");
});


(9)信号量,同步机制,控制线程执行流程。可以和操作系统中的信号量联系起来理解。
//信号量
/**
*  创建一个信号量。参数指定信号量的起始值。这个数字是你可以访问的信号量,不需要先去增加它的数量(增加信号量也叫作发射信号量)。

初始value = 0时,信号量--,小于0,wait线程阻塞。然后执行signal,信号量++,激活wait线程。
*
*/
dispatch_semaphore_t sema = dispatch_semaphore_create(0);

dispatch_async(dispatch_get_global_queue(0, 0), ^{

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
NSLog(@"chen");
});

dispatch_async(dispatch_get_global_queue(0, 0), ^{

NSLog(@"yu");
dispatch_semaphore_signal(sema);
});


(10)同一个线程中的不同任务实现同步。
使用dispatch_barrier_queue实现。注意dispatch_barrier_queue的同步控制和线程组、信号量的同步机制是不一样的,dispatch_barrier_queue是对于同一个队列中的不同任务而言的,线程组和信号量是对于不同线程而言的。

//dispatch_barrier_async,对于同一个队列中的不同任务而言,在dispatch_barrier_async之前的先执行,在dispatch_barrier_async后面的后执行
//如下面的代码所示:1和2的执行顺序不一定,但一定在dispatch_barrier_async之前执行,3和4的执行顺序不一定,但一定在dispatch_barrier_async之后执行。
//注意dispatch_barrier_async的同步控制和线程组、信号量的同步机制粒度大小是不一样的,dispatch_barrier_async是对于同一个队列中的不同任务而言的,线程组和信号量是对于不同线程而言的。
dispatch_queue_t queue = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"1");
});

dispatch_async(queue, ^{
NSLog(@"2");
});

dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async");
});

dispatch_async(queue, ^{
NSLog(@"3");
});

dispatch_async(queue, ^{
NSLog(@"4");
});

(11)dispatch_apply是把某个代码块执行N遍。

//dispatch_apply是把某个代码块执行N遍
dispatch_apply(5, dispatch_get_global_queue(0, 0), ^(size_t index) {
NSLog(@"%zu",index);
});


GCD在项目中会经常会用到,应该需要熟练掌握。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: