iOS NSThreadGCD 线程与队列(二)

本文深入探讨了GCD(Grand Central Dispatch)的核心概念及在iOS开发中的应用场景,包括不同类型的GCD方法如dispatch_async、dispatch_sync等的区别,以及如何避免死锁、实现线程安全等问题。
//
//  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];
    }
}

/**
 * 
以下4GCD方法的区别:
 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)}
       
    });
}


//例三:我们分别用syncasync向主队列提交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  %@",
                 
@"任务123的顺序不一定",
                 
@"任务4_在中间",
                 
@"最后是56789任务顺序不一定");
    });
   
   
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_syncGCDsync共有特性,会阻塞提交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(@"读操作");
    });
   
//结论:这样写操作的时候,始终只有它这一条线程在进行。而读操作一直是并行的。这么做充分利用了多线程的优势,还不需要加锁,减少了相当一部分的性能开销。实现了读写操作的线程安全。
   
//读与读: 线程并行
   
//写与写、写与读: 必须串行同步或者使用线程锁

}


//例六: 4dispatch_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_syncdispatch_barrier_sync  都能阻塞 主队列
 
区别:dispatch_sync 不能阻塞并行队列
       dispatch_barrier_sync
可以阻塞并行队列
 */


- (
void)case8 {
   
}
- (
void)case9 {
   
}


@end

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值