[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]);
        }
    });
}

在这里插入图片描述

(四)添加依赖

我们可以从上面的内容看出,这些并发任务的顺序不能够很好地控制,如果我们想要让任务有一定的顺序该怎么办呢?比如任务4必须要在任务1完成后才能进行,这要如何控制呢?
这其实就是任务4依赖于任务1,也就是可以通过添加依赖来控制。

- (void)blockOperation {
 
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 封装操作
    NSBlockOperation *blcp1 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务1
        NSLog(@"任务1---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp2 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务2
        NSLog(@"任务2---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp3 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务3
        NSLog(@"任务3---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp4 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务4
        NSLog(@"任务4---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp5 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务5
        NSLog(@"任务5---%@", [NSThread currentThread]);
    }];
    // 添加操作依赖
    [blcp3 addDependency:blcp1];  // blcp3依赖于blcp1
    [blcp1 addDependency:blcp5];  // blcp1依赖于blcp5
    [blcp5 addDependency:blcp2];  // blcp5依赖于blcp2
    [blcp2 addDependency:blcp4];  // blcp2依赖于blcp4
 
    // 将所有的任务添加到队列中
    [queue addOperation:blcp1];
    [queue addOperation:blcp2];
    [queue addOperation:blcp3];
    [queue addOperation:blcp4];
    [queue addOperation:blcp5];
}

可以看到,这上面几个任务互相添加了依赖。推断一下,进行的顺序会是什么呢?

4->2->5->1->3

看看结果:
在这里插入图片描述
果然。
这上面是单个queue的依赖。如果我们在多个队列添加多个任务呢?

- (void)blockOperation2 {
 
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];
    // 封装操作
    NSBlockOperation *blcp1 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务1
        NSLog(@"任务1---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp2 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务2
        NSLog(@"任务2---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp3 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务3
        NSLog(@"任务3---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp4 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务4
        NSLog(@"任务4---%@", [NSThread currentThread]);
    }];
    NSBlockOperation *blcp5 = [NSBlockOperation blockOperationWithBlock:^{
        // 封装任务5
        NSLog(@"任务5---%@", [NSThread currentThread]);
    }];
    // 添加操作依赖
    [blcp3 addDependency:blcp1];
    [blcp1 addDependency:blcp5];
    [blcp5 addDependency:blcp2];
    [blcp2 addDependency:blcp4];
//    [blcp4 addDependency:blcp3];  // 循环依赖,运行程序以后无响应
    
    // 将所有的任务添加到队列中
    [queue addOperation:blcp1];
    [queue2 addOperation:blcp2];  // 将blcp2添加到queue2中
    [queue addOperation:blcp3];
    [queue2 addOperation:blcp4];  // 将blcp4添加到queue2中
    [queue addOperation:blcp5];
//在上面的代码中,我们新创建了一个队列queue2,
//并且将blcp2和blcp4添加到queue2中,
//其它的操作任然放在queue中,
//但是,程序运行以后,其结果依然和上面在一个队列中添加操作依赖时一样
}

发现还是一样的结果:
在这里插入图片描述

(五)其他

对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压入当前队列。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值