//
// GCD_ViewController.m
// ZM_NSThreadGCD
//
// Created by ZM on 2015/2/9.
// Copyright © 2015年 ZM. All rights reserved.
//
#import "GCD_ViewController.h"
#import "BaseHeader.h"
@interface GCD_ViewController ()
@end
@implementation GCD_ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"GCD_VC";
NSString *title=@"";
CGFloat width = 120;
for (int i=1 ; i<11; i++) {
title = [NSString stringWithFormat:@"case%d",i];
[self addBtnTitle:title frame:CGRectMake(10, 50+ (35+10)*i, width, 35) Tag:i];
}
CGFloat yy = SSHEIGHT-90;
[self addBtnTitle:@"attentionCase3_1" frame:CGRectMake(10, yy, width, 35) Tag:111];
[self addBtnTitle:@"attentionCase3_2" frame:CGRectMake(10*2+width, yy, width, 35) Tag:222];
[self addBtnTitle:@"solveCase3_1" frame:CGRectMake(10, yy+45, width, 35) Tag:333];
}
- (void)myBtnClick:(UIButton *)Btn{
if (Btn.tag==1) { [self case1];
}else if (Btn.tag==2) { [self case2];
}else if (Btn.tag==3) { [self case3];
}else if (Btn.tag==4) { [self case4];
}else if (Btn.tag==5) { [self case5];
}else if (Btn.tag==6) { [self case6];
}else if (Btn.tag==7) { [self case7];
}else if (Btn.tag==8) { [self case8];
}else if (Btn.tag==9) { [self case9];
}
if (Btn.tag==111) { [self attentionCase3_1];
}else if (Btn.tag==222) { [self attentionCase3_2];
}else if (Btn.tag==333) { [self solveCase3_1];
}
}
/**
* 以下4个GCD方法的区别:
dispatch_async 异步任务
dispatch_sync 同步任务
dispatch_barrier_async 为异步执行调度队列:提交一个路障
dispatch_barrier_sync 为同步执行调度队列:提交一个路障
dispatch_get_main_queue 主队列
dispatch_queue_t 并行队列
dispatch_get_global_queue 全局并行队列
*/
//例一:dispatch_sync 同步任务 提交Block在 主线程 中执行
- (void)case1 {
dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue1, ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 1, name = main}
});
}
//例二:dispatch_async 异步任务 提交Block在 分线程 中执行
- (void)case2 {
dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 3, name = (null)}
});
}
//例三:我们分别用sync和async向主队列提交Block,结果Block都是在主线程中执行:
- (void)case3 {
//我们用sync如下的方式去提交Block:
dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 1, name = main}
});
});
}
//注意 3_1:在主线程 不能用sync(同步)提交Block执行任务,否则会引起死锁:
- (void)attentionCase3_1 {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"任务一");
});
NSLog(@"任务二");
//因为往queue中提交Block,总是追加在队列尾部的,而queue执行Block的顺序为先进先出(FIFO),所以任务一需要在当前队列它之前的任务(任务二)全部执行完,才能轮到它。
//任务一等待任务二完成,任务二等待任务一完成,相互等待_被阻塞,程序被死锁在这了
}
//注意 3_2:在主线程 能用async(异步)提交Block执行任务
- (void)attentionCase3_2 {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 1, name = main}
});
}
//解决 3_1 问题
- (void)solveCase3_1 {
// 全局并行队列
// 这应该是唯一一个并行队列, 只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
// 因为全局队列和主队列是两个队列,所以任务一的执行,并不需要等待任务二。
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任务一");
});
NSLog(@"任务二");
}
//例四: 建立栅栏_执行任务 dispatch_barrier_async
- (void)case4 {
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任务1");
});
dispatch_async(queue, ^{
NSLog(@"任务2");
});
dispatch_async(queue, ^{
NSLog(@"任务3");
});
//建立栅栏_执行任务 dispatch_barrier_async
dispatch_barrier_async(queue, ^{
NSLogline(@"\n %@\n %@\n %@",
@"任务1,2,3的顺序不一定",
@"任务4_在中间",
@"最后是5、6、7、8、9任务顺序不一定");
});
dispatch_async(queue, ^{
NSLog(@"任务5");
});
dispatch_async(queue, ^{
NSLog(@"任务6");
});
dispatch_async(queue, ^{
NSLog(@"任务7");
});
dispatch_async(queue, ^{
NSLog(@"任务8");
});
dispatch_async(queue, ^{
NSLog(@"任务9");
});
//结论: dispatch_barrier_async 它的作用可以用一个词概括--承上启下,它保证此前的任务都先于自己执行,此后的任务也迟于自己执行。当然它的作用导致它只有在并行队列中有意义。
//注意:当然这里有一点需要注意的是:dispatch_barrier_(a)sync只在自己创建的并发队列上有效,在全局(Global)并发队列、串行队列上,效果跟dispatch_(a)sync效果一样。
//3)dispatch_barrier_sync这个方法和dispatch_barrier_async作用几乎一样,都可以在并行queue中当做栅栏。
//唯一的区别就是:dispatch_barrier_sync有GCD的sync共有特性,会阻塞提交Block的当前线程,而dispatch_barrier_async是异步提交,不会阻塞。
}
//例五:例如我们在一个读写操作中,我们就可以如下使用:
- (void)case5 {
//一个读写操作中:我们要知道一个数据,读与读之间是可以用线程并行的,但是写与写、写与读之间,就必须串行同步或者使用线程锁来保证线程安全。但是我们有了dispatch_barrier_async
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"读操作_1");
});
dispatch_async(queue, ^{
NSLog(@"读操作_2");
});
dispatch_barrier_async(queue, ^{
NSLog(@"写操作_1");
});
dispatch_barrier_async(queue, ^{
NSLog(@"写操作_2");
});
dispatch_async(queue, ^{
NSLog(@"读操作");
});
//结论:这样写操作的时候,始终只有它这一条线程在进行。而读操作一直是并行的。这么做充分利用了多线程的优势,还不需要加锁,减少了相当一部分的性能开销。实现了读写操作的线程安全。
//读与读: 线程并行
//写与写、写与读: 必须串行同步或者使用线程锁
}
//例六: 4)dispatch_sync,我们来讲讲它和dispatch_barrier_sync的区别。二者因为是sync提交,所以都是阻塞当前提交Block线程。
//而它俩唯一的区别是:dispatch_sync并不能阻塞并行队列。其实之前死锁有提及过,担心大家感觉疑惑,还是写个例子:
- (void)case6 {
dispatch_queue_t queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
// dispatch_sync
dispatch_sync(queue, ^{
dispatch_async(queue, ^{
NSLog(@"任务二");
});
dispatch_async(queue, ^{
NSLog(@"任务三");
});
//睡眠2秒
// [NSThread sleepForTimeInterval:2];
NSLog(@"任务一 \n ");
});
//输出结果: 任务三 任务二 任务一 (二、三顺序不固定,一最后,很显然,并行队列没有被sync所阻塞。)
}
//例七:而 dispatch_barrier_sync 可以阻塞并行队列(栅栏作用的体现):
- (void)case7 {
dispatch_queue_t queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
// dispatch_barrier_sync
dispatch_barrier_sync(queue, ^{
dispatch_async(queue, ^{
NSLog(@"任务二");
});
dispatch_async(queue, ^{
NSLog(@"任务三");
});
//睡眠2秒
// [NSThread sleepForTimeInterval:2];
NSLog(@"任务一");
});
//输出结果: 任务一 任务二 任务三 (一首先,二、三顺序不固定)
}
/**
同:dispatch_sync、dispatch_barrier_sync 都能阻塞 主队列
区别:dispatch_sync 不能阻塞并行队列
dispatch_barrier_sync 可以阻塞并行队列
*/
- (void)case8 {
}
- (void)case9 {
}
@end
// GCD_ViewController.m
// ZM_NSThreadGCD
//
// Created by ZM on 2015/2/9.
// Copyright © 2015年 ZM. All rights reserved.
//
#import "GCD_ViewController.h"
#import "BaseHeader.h"
@interface GCD_ViewController ()
@end
@implementation GCD_ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"GCD_VC";
NSString *title=@"";
CGFloat width = 120;
for (int i=1 ; i<11; i++) {
title = [NSString stringWithFormat:@"case%d",i];
[self addBtnTitle:title frame:CGRectMake(10, 50+ (35+10)*i, width, 35) Tag:i];
}
CGFloat yy = SSHEIGHT-90;
[self addBtnTitle:@"attentionCase3_1" frame:CGRectMake(10, yy, width, 35) Tag:111];
[self addBtnTitle:@"attentionCase3_2" frame:CGRectMake(10*2+width, yy, width, 35) Tag:222];
[self addBtnTitle:@"solveCase3_1" frame:CGRectMake(10, yy+45, width, 35) Tag:333];
}
- (void)myBtnClick:(UIButton *)Btn{
if (Btn.tag==1) { [self case1];
}else if (Btn.tag==2) { [self case2];
}else if (Btn.tag==3) { [self case3];
}else if (Btn.tag==4) { [self case4];
}else if (Btn.tag==5) { [self case5];
}else if (Btn.tag==6) { [self case6];
}else if (Btn.tag==7) { [self case7];
}else if (Btn.tag==8) { [self case8];
}else if (Btn.tag==9) { [self case9];
}
if (Btn.tag==111) { [self attentionCase3_1];
}else if (Btn.tag==222) { [self attentionCase3_2];
}else if (Btn.tag==333) { [self solveCase3_1];
}
}
/**
* 以下4个GCD方法的区别:
dispatch_async 异步任务
dispatch_sync 同步任务
dispatch_barrier_async 为异步执行调度队列:提交一个路障
dispatch_barrier_sync 为同步执行调度队列:提交一个路障
dispatch_get_main_queue 主队列
dispatch_queue_t 并行队列
dispatch_get_global_queue 全局并行队列
*/
//例一:dispatch_sync 同步任务 提交Block在 主线程 中执行
- (void)case1 {
dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue1, ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 1, name = main}
});
}
//例二:dispatch_async 异步任务 提交Block在 分线程 中执行
- (void)case2 {
dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 3, name = (null)}
});
}
//例三:我们分别用sync和async向主队列提交Block,结果Block都是在主线程中执行:
- (void)case3 {
//我们用sync如下的方式去提交Block:
dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 1, name = main}
});
});
}
//注意 3_1:在主线程 不能用sync(同步)提交Block执行任务,否则会引起死锁:
- (void)attentionCase3_1 {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"任务一");
});
NSLog(@"任务二");
//因为往queue中提交Block,总是追加在队列尾部的,而queue执行Block的顺序为先进先出(FIFO),所以任务一需要在当前队列它之前的任务(任务二)全部执行完,才能轮到它。
//任务一等待任务二完成,任务二等待任务一完成,相互等待_被阻塞,程序被死锁在这了
}
//注意 3_2:在主线程 能用async(异步)提交Block执行任务
- (void)attentionCase3_2 {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%@",[NSThread currentThread]); //输出结果:{number = 1, name = main}
});
}
//解决 3_1 问题
- (void)solveCase3_1 {
// 全局并行队列
// 这应该是唯一一个并行队列, 只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。
// 因为全局队列和主队列是两个队列,所以任务一的执行,并不需要等待任务二。
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"任务一");
});
NSLog(@"任务二");
}
//例四: 建立栅栏_执行任务 dispatch_barrier_async
- (void)case4 {
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"任务1");
});
dispatch_async(queue, ^{
NSLog(@"任务2");
});
dispatch_async(queue, ^{
NSLog(@"任务3");
});
//建立栅栏_执行任务 dispatch_barrier_async
dispatch_barrier_async(queue, ^{
NSLogline(@"\n %@\n %@\n %@",
@"任务1,2,3的顺序不一定",
@"任务4_在中间",
@"最后是5、6、7、8、9任务顺序不一定");
});
dispatch_async(queue, ^{
NSLog(@"任务5");
});
dispatch_async(queue, ^{
NSLog(@"任务6");
});
dispatch_async(queue, ^{
NSLog(@"任务7");
});
dispatch_async(queue, ^{
NSLog(@"任务8");
});
dispatch_async(queue, ^{
NSLog(@"任务9");
});
//结论: dispatch_barrier_async 它的作用可以用一个词概括--承上启下,它保证此前的任务都先于自己执行,此后的任务也迟于自己执行。当然它的作用导致它只有在并行队列中有意义。
//注意:当然这里有一点需要注意的是:dispatch_barrier_(a)sync只在自己创建的并发队列上有效,在全局(Global)并发队列、串行队列上,效果跟dispatch_(a)sync效果一样。
//3)dispatch_barrier_sync这个方法和dispatch_barrier_async作用几乎一样,都可以在并行queue中当做栅栏。
//唯一的区别就是:dispatch_barrier_sync有GCD的sync共有特性,会阻塞提交Block的当前线程,而dispatch_barrier_async是异步提交,不会阻塞。
}
//例五:例如我们在一个读写操作中,我们就可以如下使用:
- (void)case5 {
//一个读写操作中:我们要知道一个数据,读与读之间是可以用线程并行的,但是写与写、写与读之间,就必须串行同步或者使用线程锁来保证线程安全。但是我们有了dispatch_barrier_async
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"读操作_1");
});
dispatch_async(queue, ^{
NSLog(@"读操作_2");
});
dispatch_barrier_async(queue, ^{
NSLog(@"写操作_1");
});
dispatch_barrier_async(queue, ^{
NSLog(@"写操作_2");
});
dispatch_async(queue, ^{
NSLog(@"读操作");
});
//结论:这样写操作的时候,始终只有它这一条线程在进行。而读操作一直是并行的。这么做充分利用了多线程的优势,还不需要加锁,减少了相当一部分的性能开销。实现了读写操作的线程安全。
//读与读: 线程并行
//写与写、写与读: 必须串行同步或者使用线程锁
}
//例六: 4)dispatch_sync,我们来讲讲它和dispatch_barrier_sync的区别。二者因为是sync提交,所以都是阻塞当前提交Block线程。
//而它俩唯一的区别是:dispatch_sync并不能阻塞并行队列。其实之前死锁有提及过,担心大家感觉疑惑,还是写个例子:
- (void)case6 {
dispatch_queue_t queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
// dispatch_sync
dispatch_sync(queue, ^{
dispatch_async(queue, ^{
NSLog(@"任务二");
});
dispatch_async(queue, ^{
NSLog(@"任务三");
});
//睡眠2秒
// [NSThread sleepForTimeInterval:2];
NSLog(@"任务一 \n ");
});
//输出结果: 任务三 任务二 任务一 (二、三顺序不固定,一最后,很显然,并行队列没有被sync所阻塞。)
}
//例七:而 dispatch_barrier_sync 可以阻塞并行队列(栅栏作用的体现):
- (void)case7 {
dispatch_queue_t queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
// dispatch_barrier_sync
dispatch_barrier_sync(queue, ^{
dispatch_async(queue, ^{
NSLog(@"任务二");
});
dispatch_async(queue, ^{
NSLog(@"任务三");
});
//睡眠2秒
// [NSThread sleepForTimeInterval:2];
NSLog(@"任务一");
});
//输出结果: 任务一 任务二 任务三 (一首先,二、三顺序不固定)
}
/**
同:dispatch_sync、dispatch_barrier_sync 都能阻塞 主队列
区别:dispatch_sync 不能阻塞并行队列
dispatch_barrier_sync 可以阻塞并行队列
*/
- (void)case8 {
}
- (void)case9 {
}
@end
本文深入探讨了GCD(Grand Central Dispatch)的核心概念及在iOS开发中的应用场景,包括不同类型的GCD方法如dispatch_async、dispatch_sync等的区别,以及如何避免死锁、实现线程安全等问题。
400

被折叠的 条评论
为什么被折叠?



