[OC学习笔记]浅学GCD线程相关内容

Posted Billy Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[OC学习笔记]浅学GCD线程相关内容相关的知识,希望对你有一定的参考价值。

一、学点基础知识

(一)Queue队列:

Queue队列分为几下几种:

1、全局队列:

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

2、主队列:

dispatch_get_main_queue()

3、用户创建的串行队列:

dispatch_queue_create(“com.yuna.com”, DISPATCH_QUEUE_SERIAL/NULL);

4、用户创建的并行队列:

dispatch_queue_create(“com.yuna.com”, DISPATCH_QUEUE_CONCURRENT);

(二)同步与异步

1. 同步

dispatch_sync(queue,block):同步队列,dispatch_sync函数不会立即返回,会阻塞当前线程,将block放到指定的queue上面执行,等待该block同步执行完成后才会返回

2. 异步

dispatch_async(queue,block):异步队列,dispatch_async函数会立即返回,block放到指定queue中等待执行,该block是并行还是串行只跟queue定义有关

(三)看看组合情况

/*
 串行队列 + 同步任务:没有开启新线程,任务是逐个完成的
 */
- (void)serialSync 
    dispatch_queue_t queue = dispatch_queue_create("com.pi2e.com", DISPATCH_QUEUE_SERIAL);
    NSLog(@"串行队列 + 同步----%@",[NSThread currentThread]);
//    dispatch_queue_t queue = dispatch_queue_create("com.pi2e.com", NULL);
    //在队列里添加同步任务
    dispatch_sync(queue, ^
        for (int  i = 0; i < 5; i++) 
            NSLog(@"---1--%@", [NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int  i = 0; i < 5; i++) 
            NSLog(@"---2--%@", [NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"---3--%@", [NSThread currentThread]);
        
    );

/*
 串行队列 + 异步任务:开启新线程,任务是逐个完成的
 */
- (void)serialAsync 
    dispatch_queue_t queue = dispatch_queue_create("com.pi2e.com", DISPATCH_QUEUE_SERIAL);
    //    dispatch_queue_t queue = dispatch_queue_create("com.pi2e.com", NULL);
    NSLog(@"串行队列 + 异步----%@",[NSThread currentThread]);
    //在队列里添加异步任务
    dispatch_async(queue, ^
        for(int  i = 0; i < 5;i++) 
            NSLog(@"---1--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for(int  i = 0; i < 5; i++) 
            NSLog(@"---2--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for(int  i = 0; i < 5; i++) 
            NSLog(@"---3--%@", [NSThread currentThread]);
        
    );

/*
 并发队列 + 同步任务 :没有开启新线程,任务是逐个执行
 */
- (void)createConCurrentQueueSyn 
    //创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("com.pi2e.com", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"并发队列 + 同步----%@",[NSThread currentThread]);
    //在队列里添加同步任务
    dispatch_sync(queue, ^
        for (int  i = 0 ; i < 5;i++)
            NSLog(@"---1--%@",[NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int  i=0 ; i < 5;i++) 
            NSLog(@"---2--%@",[NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int  i=0 ; i < 5;i++)
            NSLog(@"---3--%@",[NSThread currentThread]);
        
    );

/*
 并发队列 + 异步任务 :开启新线程,任务是并发的
*/

- (void)createConCurrentQueueAsyn 
    
    dispatch_queue_t queue = dispatch_queue_create("com.pi2e.com", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"并发队列 + 异步----%@", [NSThread currentThread]);
    //队列中添加异步任务
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--1--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--2--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--3--%@", [NSThread currentThread]);
        
    );

/*
 全局队列 + 同步任务:,没有开启新线程,任务逐个执行
 */
- (void)GlabolSyc 
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@"全局队列 + 同步----%@",[NSThread currentThread]);
    //在队列里添加同步任务
    dispatch_sync(queue, ^
        for (int i=0 ; i < 5; i++) 
            NSLog(@"---1--%@", [NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int i=0 ; i < 5; i++) 
            NSLog(@"---2--%@", [NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int i=0 ; i < 5; i++) 
            NSLog(@"---3--%@", [NSThread currentThread]);
        
    );


/*
 全局 + 异步:开启新线程,任务是并发的
 */

- (void)GlobalAsync 
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     NSLog(@"全局队列 + 异步----%@", [NSThread currentThread]);
    //队列中添加异步任务
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--1--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--2--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--3--%@", [NSThread currentThread]);
        
    );

/*
 主队列(串行)+同步:界面卡死
 主队列中添加同步任务会造成死锁的
 */
//dispatch_sync 是指在指定线程队列queue 同步执行任务block,
//dispatch_sync具有等待block执行结束再能回调的特点;
- (void)mainthreadSync 
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"主队列(串行)+同步----%@",[NSThread currentThread]);
    //在队列里添加同步任务
    dispatch_sync(queue, ^
        for (int i = 0; i < 10; i++) 
            NSLog(@"--1--%@", [NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int i = 0; i < 10; i++) 
            NSLog(@"--2--%@", [NSThread currentThread]);
        
    );
    dispatch_sync(queue, ^
        for (int i = 0; i < 10; i++) 
            NSLog(@"--3--%@", [NSThread currentThread]);
        
    );

/*
 主队列(串行)+异步:没有创建新线程,任务逐个完成 {都是在主线程中执行的}
 */
- (void)mainthreadAsync 
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"主队列(串行)+异步----%@",[NSThread currentThread]);
    //在队列里添加异步任务
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--1--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--2--%@", [NSThread currentThread]);
        
    );
    dispatch_async(queue, ^
        for (int i = 0; i < 5; i++) 
            NSLog(@"--3--%@", [NSThread currentThread]);
        
    );

(四)其他

对NSNotificationCenter的分析

- (void)viewDidLoad 
    [super viewDidLoad];
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(passValue:) name:@"PassValue" object:nil];
    [self sentValue];
    NSLog(@"通知赋值完毕");

- (void)sentValue 
    NSLog(@"发送通知");
    NSDictionary *dict = @@"myValue":@"Billy通知传值";
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"PassValue" object:nil userInfo:dict]];


- (void)passValue:(NSNotification *)text
    NSString *valueStr = text.userInfo[@"myValue"];
    NSLog(@"收到值:%@",valueStr);
    sleep(3);


分析:
通过打印的时间我们可以看出,当我们发送通知以后,观察者在接收到值以后,休眠了3秒,程序才会继续往下执行,也就是说这个过程是同步的;这里面设计为同步,大概是考虑到,一个通知可能有多个监听者,采用同步的方式能够保证所有的观察者都能够对通知做出相应,不会遗漏。

改为异步:

- (void)sentValue 
    NSLog(@"发送通知");
    NSDictionary *dict = @@"myValue":@"Billy通知传值";
    dispatch_async(dispatch_get_main_queue(), ^
        [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:@"PassValue" object:nil userInfo:dict]];
    );

二、看看死锁

先理解几个概念:

(一)串行队列:

任务按照顺序添加在一个队列中,依次执行,常用的串行队列有主队列main queue和一般的串行队列serial queue。

(二)dispatch_sync():

同步任务,即前一个任务执行完毕,后面的任务才会开始执行,否则后面的任务都处于等待状态。

(三)死锁发生的原因:

在同一个串行队列中,如果主队列中的有个执行函数未执行完毕,恰好执行函数中通过dispatch_sync()添加同步任务,这时就会发生死锁。主队列中添加同步任务会造成死锁。也就是:主队列中的执行函数当前是作为第一个任务正在执行,必须执行完该函数,才算执行完首个任务并返回结果,此时才会向下执行后面的任务,如果此时执行函数中又通过dispatch_sync()同步添加了newTask,那么执行函数必须等刚添加的newTask执行完,才能向下执行,也就才算执行函数的调用结束,即首个任务执行完毕;而newTask作为同步添加的第二个任务,又在等待首个任务即执行函数执行完,才会开始执行,这样就出现了相互等待的情况,两个任务永远无法执行完,即出现死锁。

(四)例:

- (void)viewDidLoad 
	[super viewDidLoad];
  	dispatch_sync(dispatch_get_main_queue(), ^
      	NSLog(@"newTask");
 	);

同步对于任务是立刻执行的,那么当把任务放进主队列时,它就会立马执行,只有执行完这个任务,viewDidLoad才会继续向下执行。而viewDidLoad和任务都是在主队列上的,由于队列的先进先出原则,任务又需等待viewDidLoad执行完毕后才能继续执行,viewDidLoad和这个任务就形成了相互循环等待,就造成了死锁。想避免这种死锁,可以将同步改成异步dispatch_async,或者将dispatch_get_main_queue换成其他串行或并行队列,都可以解决。因此,不要用dispatch_sync()把block压入当前队列。

以上是关于[OC学习笔记]浅学GCD线程相关内容的主要内容,如果未能解决你的问题,请参考以下文章

[OC学习笔记]GCD复习

[OC学习笔记]多线程之GCD

[OC学习笔记]多线程之GCD

[OC学习笔记]Grand Central Dispatch

OC 线程操作 - GCD快速迭代

OC 线程操作 - GCD队列组