GCD的同异步、串并行以及队列死锁的问题

来源:互联网 发布:黑色沙漠男法捏脸数据 编辑:程序博客网 时间:2024/06/16 01:53

概念解释:

同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力

并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务

通过GCD可获得的三种队列
1.全局并发队列
2.主队列(跟主线程相关联的队列)
3.自定义队列

三种队列通过同步、异步方式,实验下6种方式:

1.全局并发队列,同步方式

- (void)count{    for (int i = 0; i < 5; i++) {        NSLog(@"num:%d",i);    }}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    //获取全局队列    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_sync(queue, ^{        NSLog(@"下载图片1---%@",    [NSThread currentThread]);        [self count];    });    dispatch_sync(queue, ^{        NSLog(@"下载图片2---%@",    [NSThread currentThread]);        [self count];    });}

运行结果:
这里写图片描述
number = 1表示当前是主线程,因为是dispatch_sync同步方式往全局队列中添加的任务,可见并没有开启新的线程。

2.全局并发队列,异步方式

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_async(queue, ^{        NSLog(@"下载图片3---%@",    [NSThread currentThread]);        [self count];    });    dispatch_async(queue, ^{        NSLog(@"下载图片4---%@",    [NSThread currentThread]);        [self count];    });}

运行结果:

这里写图片描述

可以看到number =4,number = 3,意味着开启了两个子线程去完成任务,观察num:0 num:0 ,交替打印出num的值,可以理解为两个任务同时进行,即并行处理

3.主队列,同步方式

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    dispatch_queue_t queue = dispatch_get_main_queue();    dispatch_sync(queue, ^{        NSLog(@"下载图片1---%@",    [NSThread currentThread]);        [self count];    });    dispatch_sync(queue, ^{        NSLog(@"下载图片2---%@",    [NSThread currentThread]);        [self count];    });}

这里运行,看起来并没有什么反应,也没有什么什么结果在Xcode上打印出来,为什么呢?这里涉及到串行队列中执行串行同步操作造成死锁的问题。

*首先大环境是主队列(主队列本质是串行队列 遵循FIFO),在主队列中,使用同步函数在主队列(相当于在相同的串行队列)末尾加入了任务。主队列 遇到了同步函数,准备继续往下执行程序,但是同步函数这时候也要执行,这意味着程序需要等待同步函数执行完成后才能继续。那么同步函数什么时候执行完成呢?同步函数需要等它自己block中的任务执行结束,而block种的任务什么时候执行结束呢?根据串行队列FIFO原则,要等待主队列中block这个任务前面所有的任务完成,而block任务是在主队列队尾,block前面的任务至少还有一个同步函数dispatch_sync()这个任务,所以block必须等待dispatch_sync()执行完。 那么问题来了,dispatch_sync()等待block执行完,block又在等待dispatch_sync()执行完,互相等待,这就造成死锁了。主要原因是主队列是串行队列。

4.主队列,异步方式

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    [self count];    dispatch_queue_t queue = dispatch_get_main_queue();    dispatch_async(queue, ^{        NSLog(@"下载图片3---%@",    [NSThread currentThread]);        [self count];    });    dispatch_async(queue, ^{        NSLog(@"下载图片4---%@",    [NSThread currentThread]);        [self count];    });}

这里写图片描述

分析一下:
*异步方式开启,等主线程执行完操作,才处理主队列中的任务
*虽然是异步方式,但是number = 1,并没有开启新的线程

5.自创建串行队列,同步方式

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);    dispatch_sync(queue, ^{        NSLog(@"下载图片1---%@",    [NSThread currentThread]);        [self count];    });    dispatch_sync(queue, ^{        NSLog(@"下载图片2---%@",    [NSThread currentThread]);        [self count];    });}


*同步方式,串行队列,没有开启新线程。
*由于同步函数不具备开启新线程的能力,所以就不列举同步函数执行并发队列的 例子了。

这里写图片描述

6.自创建并发队列,异步方式

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);    dispatch_sync(queue, ^{        NSLog(@"下载图片1---%@",    [NSThread currentThread]);        [self count];    });    dispatch_sync(queue, ^{        NSLog(@"下载图片2---%@",    [NSThread currentThread]);        [self count];    });}

这里写图片描述

*异步方式,观察number =3,number=4,意味着,开启了两个新的线程处理任务
*num打印的值来看,由于创建的并发队列,所以并行处理。类似例子1中的全局队列,同步方式。

小结

方式 全局队列 主队列 自创建队列 同步 未开启新线程,串行执行任务 未开启新线程,串行执行任务 未开启新线程,串行执行任务 异步 开启新线程,并发执行任务 开启新线程,串行执行任务 未开启新线程,串行执行任务
1 0
原创粉丝点击