iOS-GCD多线程编程详解1

文明看博转载是对自己的尊重也是对学者的鼓励,欢迎讨论

iOS-GCD多线程编程详解


一.前言

前面的多线程编程中分别讲到NSThread和NSOperation的多线程编程,本张主要是讲述GCD的编程,GCD的多线程编程是基于BLock或者函数包裹多线程任务,由系统管理线程实现的,因此其低耦合,容易使用,又是基于C语言实现,运行速度快,是官方推荐的多线程实现的首先方案,至于个人什么顺手就用什么。


二.GCD多线程使用说明


在多线程编程中,首先要考虑的问题是多线程任务写在什么地方,同步还是异步,是在主线程中执行还是在子线程中执行,多线程任务的依赖关系,执行的先后顺序,是自己创建线程还是系统的线程承载线程任务的执行,是自己管理线程还是系统管理,对于GCD而言,多线程任务通过Block或者函数来包含多线程任务,它的依赖和执行顺序有特定的GCD函数,它的任务承载线程是有系统生成和管理,所以用户只需要关心多线程任务是使用block还是函数包裹,是使用同步还是异步,是在主线程上执行还是在子线程上执行。


1.dispathc_sync:

该函数的作用是提交一个block到指定的dispatch_queue中,直到block执行结束返回,在主线程中使用该函数就会造成UI卡住:

note:下面这段代码是在主线程中调用

NSLog(@"before dispatch_sync");<span style="white-space:pre">				</span>//主线程中调用
    dispatch_sync(dispatch_get_main_queue(), ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"hello world");<span style="white-space:pre">	</span>//这条语句没有被执行
        });
    });
运行结果:

2015-01-03 17:45:58.213 GCDTest[1750:140657] before dispatch_sync(还有就是界面卡死了,因为形成了死锁)


note:下面的这段代码是在非主线程中调用:

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [NSThread detachNewThreadSelector:@selector(netThread:) toTarget:self withObject:@"new thread"];  //子线程分支
    NSLog(@"hello world main");
    
}
-(void)netThread:(id)sender{
    NSLog(@"before dispatch_sync");
    dispatch_sync(dispatch_get_main_queue(), ^{<span style="white-space:pre">			</span>//相当于在主线程中调用dispatch_sync
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"hello world subThread");<span style="white-space:pre">	</span>//从结果中看出这条语句没有被运行
        });
    });
}
@end

运行结果:

2015-01-04 17:37:04.426 GCDTest[1869:155469] before dispatch_sync(屏幕卡死)

2015-01-04 17:37:04.426 GCDTest[1869:155423] hello world main

所以在使用disatich_sync时不要在UI线程使用。


相似函数:

dispatch_sync_f:该函数提交的是一个函数任务,相当于dispatch_sync:提交block,说白了把提交的function相当于block,有兴趣的可以看我其中的一篇BLock揭秘,了解函数和block的一些映射个人思想。

 dispatch_async_f(dispatch_get_main_queue(), nil, fun_my);
    
}

static void fun_my(void *hel){
    NSLog(@"function");
}
运行结果:

2015-01-04 00:53:48.894 GCDTest[2010:161173] function   


在主线程中使用的dispatch_sync(dispatch_get_main_queue,^{})形成死锁图解:



dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"我是异步的block1,我被装在dispatch_get_main_queue中");
    });
    
    NSLog(@"我是主线程,我的源代码位置被写在block1的后面");

运行结果:

2015-01-04 22:37:31.821 GCDTest[713:28383] 我是主线程,我的源代码位置被写在block1的后面

2015-01-04 22:37:31.836 GCDTest[713:28383] 我是异步的block1,我被装在dispatch_get_main_queue

图解分析:




三.各个GCD函数使用详解


通过上一节的简单使用,我们可以把GCD分解为线程任务包装:block,function,线程任务的容器:dispatch_queue(序列类型和并发类型),同步和异步(重点是异步的实现);block可以参考点击打开链接,function就是一般的函数,同步和异步就是同步执行和异步执行,下面通过代码来了解block的容器-------dispatch_queue.

1.dispatch_global_queue

dispatch_group_t group2 = dispatch_group_create();
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block1 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block2 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block3 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block4 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group2, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"*block5 运行在线程%@",[NSThread currentThread]);
    });

运行结果:

1:

2015-01-04 23:04:37.273 GCDTest[850:36850] *block2 运行在线程<NSThread: 0x7fc2d9c6e350>{number = 5, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36848] *block3 运行在线程<NSThread: 0x7fc2d9c6b200>{number = 3, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36849] *block4 运行在线程<NSThread: 0x7fc2d9f269a0>{number = 4, name = (null)}

2015-01-04 23:04:37.274 GCDTest[850:36854] *block5 运行在线程<NSThread: 0x7fc2d9c6d180>{number = 6, name = (null)}

2015-01-04 23:04:37.273 GCDTest[850:36847] *block1 运行在线程<NSThread: 0x7fc2d9d1ce30>{number = 2, name = (null)}

2:

2015-01-04 23:07:09.728 GCDTest[858:37701] *block2 运行在线程<NSThread: 0x7fc569406f40>{number = 4, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37700] *block3 运行在线程<NSThread: 0x7fc56940da90>{number = 5, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37698] *block1 运行在线程<NSThread: 0x7fc5694182a0>{number = 2, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37699] *block4 运行在线程<NSThread: 0x7fc56952c740>{number = 3, name = (null)}

2015-01-04 23:07:09.728 GCDTest[858:37704] *block5 运行在线程<NSThread: 0x7fc569713820>{number = 6, name = (null)}

。。。

运行结果每次都不同,所在的运行线程也不同,所以dispatch_global_queue是并行的系统维护的线程依次冲队列中取出block执行


2.dispatch_main_queue

dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block1 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block2 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block3 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block4 运行在线程%@",[NSThread currentThread]);
    });
    
    dispatch_group_async(group, dispatch_get_main_queue(), ^{
        NSLog(@"block5 运行在线程%@",[NSThread currentThread]);
    });

运行结果:

2015-01-04 23:07:09.762 GCDTest[858:37660] block1 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block2 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block3 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.762 GCDTest[858:37660] block4 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

2015-01-04 23:07:09.763 GCDTest[858:37660] block5 运行在线程<NSThread: 0x7fc569613060>{number = 1, name = main}

运行结果每次都是一致的,说明dispatch_main_queue是根据其加入顺序执行的执行的线程为主线程;


所以顺序队列和并行队列的对比图如下:


小结:这篇博文主要说了关于顺序队列和并行队列的block容器的特性,后面将会陆续的对GCD的多线程编程有详细的使用。

引用或者转载请注明出处,是对自己的尊重也是对学者的鼓励。


posted @ 2015-01-04 23:48  fineman  阅读(179)  评论(0编辑  收藏  举报