//
// 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