通过本小说你会到:

  • 正文的著述指标是为学习记录,同一时间享受给大家,希望大神能够对文中错误的通晓举行指正。

GCD(Grand Central
Dispatch)是iOS多职务的基本,它能够让程序猿不用直接加入到线程的始建和护卫中,而让操作系统来间接管理线程的创建和管理,让多职分的开辟特别简明。

小说资料来源于《Objective-C高档编制程序》之GCD

1.GCD中的一些基础数据类型

  • 二十四线程编制程序个中的基本概念
  • 怎么样预防GCD多线程的读写难点
  • 要是小说内容涉及到别的已经刊登了,但作品中又未谈到转发事项,请马上与自家联系。
  • 本文为个人明白,如若有个别知识点与真真实景况况有出入,请忽略本文。

在GCD中,操作就是贰个代码块,而队列(dispatch_queue)就是寄存这一个操作的地点,要专注,队列并非线程,队列是集体操作的,调用dispatch_async并不会让操作起来施行,而只是把操作加多到行列的尾声,当操作达到队列头时,操作才会初叶实施。增添到行列中的操作不可能撤消。

GCD是一种异步实行任务的技巧,对于编制程序层面上异步实施就表示成立三个线程(操作系统能夠進行運算调解的矮小單位,是经过中多个单纯顺序的支配流–from
wiki)去实施Task;GCD提供了三种队列和血脉相通API使得开拓者只需求关怀该选用哪一类队列去试行义务就能够;

/*
 GCD中一些基础数据类型
 dispatch_time_t:dispatch_walltime获得真实时间(绝对时间),dispatch_time获得马赫时间
 */
dispatch_time_t time = dispatch_walltime(NULL, 0);
NSLog(@"%lld", time);
dispatch_time_t time2 = dispatch_time(0, 1 * NSEC_PER_SEC);
NSLog(@"%lld", time2);
dispatch_time_t time3 = DISPATCH_TIME_NOW;
NSLog(@"%lld", time3);

GCD是Grand Central Dispatch的简称。为何使用GCD?

1 iOS和OS X中八线程基本概念

开创队列

使用dispatch_queue_create(constchar *label,dispatch_queue_attr_t attr)来创设队列,第三个参数是队列的标示符,第1个参数则钦命队形是串行队列(DISPATCH_QUEUE_SERIAL)还是并发队列(DISPATCH_QUEUE_CONCURRENT),不管是串行队列照旧出现队列,队列中的操作都选拔FIFO的法子收取实践,不一样的是并发队列能够将队列中的多少个操作收取并放置不相同的线程中施行。

GCD的队列

  • serial queue
    能够确认保证各类task在同一个线程中被试行而且实行顺序会严苛的依据入队的一一举办;
  • concurrent queue
    各样task的实施互不影响,施行种种上不鲜明,施行线程也不必然会雷同;

2.串行、并行和同步、异步的概念

选拔GCD具备以下好处:

1.1 了解GCD

获得队列

能够选拔dispatch_get_main_queue()得到主队列,主队列是三个串行队列,队列中的全数操作都以在主线程中试行的;系统中留存有全局并发队列,使用dispatch_get_global_queue(long identifier, unsigned long flags)获取全局并发队列,使用第二个参数选用优先级:

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0#define DISPATCH_QUEUE_PRIORITY_LOW  #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

GCD会根据可用线程尽恐怕的从高优先级队列收取操作并实施,等高优先级队列空了今后,继续从暗中同意优先级队列中抽出操作并施行,就那样类推。

操作有二种实施情势:联机试行异步实行。使用dispatch_sync(dispatch_queue_t queue, dispatch_block_t block)进展共同举办操作,使用dispatch_async(dispatch_queue_t queue,dispatch_block_t block)进展异步奉行操作。使用异步奉行操作,系统会将block加多到行列queue中,而一旦运用同步实施操作,系统则会先堵塞当前的线程,再将block增添到行列queue中,等block推行完了,当前线程才会撤废阻塞。需求稳重同步施行很轻松会出现死锁的情状:

dispatch_sync(dispatch_get_main_queue(), ^{ //同步执行 NSLog;});

这段代码看似没分外,但即便当前线程是主线程的话,则会先堵塞主线程,等待block试行完,而block却是在主线中实践的,所以block中的代码永久不会被试行,何况主线程也会被直接不通。

dispatch_queue_create 创设队列

serial queue

  /*
 1>serial Queue:系统默认创建一个线程,队列中的任务是顺序执行
 2>创建多个serial queue 的执行是并发的没有顺序
 3>解决数据竞争问题:可以将任务放在serial queue中 保证任务按照顺序执行就能解决数据竞争
*/
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.hua.example.serialQueue", DISPATCH_QUEUE_SERIAL);

concurrent queue

 /*
  1 concurrent queue 添加到队列中的任务会并发执行,没有顺序性
 */
dispatch_queue_t myConcurrentQueue=dispatch_queue_create("com.hua.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

非ARC下转移的体系还非得利用dispatch_release(Queue);来刑释钦赐的队列

/*
 串行(serial):只有在上一个任务执行完才会执行下一个任务
 并行(concurrent):多个任务同时执行
 */
/*
 同步(sync):代码执行完才会往下走(返回值,return),且不会创建新线程,而是在主线程中的,即时我们传了其他队列参数也不会创建
 异步(async):代码不需要执行完,直接可以执行下面的代码
 */
  • GCD能革新app的响应手艺,通过将一部分比较耗时的义务运维在后台(background)
  • GCD提供一个比较便于采用的现身模型。制止有个别产出引起的Bug

1.1.1 iOS和OS X中,实现二十八线程编制程序的形式。

  • NSThread,调用方便,但要求手动管理线程生命周期,作用较轻巧,适用于轻易完成四线程需要。
  • NSOperation &
    NSOperationQueue,苹果官方对GCD的卷入,完周密向对象,很有利地落到实处GCD的大多数意义。非常多大神提出,在NSOperation能促成的图景下,尽量用NSOperation实际不是GCD,因为实惠、代码可读性(帮您写好的代码,干嘛不用)。本文不予研究。
  • GCD,苹果集团为多核的相互运算建议的技术方案。基于C语言,但无需做额外的拍卖即能够一直动用。很有力的十六线程管理情势。
  • Pthreads,可在三个操作系统使用的,手动管理线程生命周期的,基于C语言的,八线程手艺。简单来说正是移植性强,不过用起来复杂。

停顿队列

能够运用dispatch_suspend(dispatch_object_t object)来行车制动器踏板队列,要留心,正在施行的操作不会被中断,只会搁浅还未起头试行的操作;对应的,使用dispatch_resume(dispatch_object_t
object)来还原执行队列。数次搁浅队列需求等量的过来操作。

队列组(dispatch_group_t)可以将职务实行分组并施行,当这组职责都试行完后,调用者能够吸收接纳公告。使用dispatch_group_create()开创队列组;使用dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);将把block增多到queue中异步实行,并代表block为group组中的操作;使用dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);吸纳group中具有操作施行到位的关照。使用dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);先堵塞当前线程,等待group中的全体操作实施完后,继续阻塞当前线程timeout大小的光阴。

例如:

dispatch_group_t group = dispatch_group_create(); dispatch_queue_t queue1 = dispatch_queue_create("1", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t queue2 = dispatch_queue_create("2", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSLog; dispatch_group_async(group, queue1, ^{ for (int i = 0; i < 3; i++) { NSLog(@"操作1-%d", i); }}); dispatch_group_async(group, queue2, ^{ for (int i = 0; i < 3; i++) { NSLog(@"操作2-%d", i); }});dispatch_group_async(group, queue3, ^{ for (int i = 0; i < 3; i++) { NSLog(@"操作3-%d", i); }}); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog;}); 

地点先创制了八个队列组和多少个并发队列,再将多个并行职务加入队列组中并实行,推行完后文告主队列更新UI。

打字与印刷结果:

015-08-12 14:28:08.275 GCDTest[2248:88609] 开始 2015-08-12 14:28:08.276 GCDTest[2248:88635] 操作1-02015-08-12 14:28:08.277 GCDTest[2248:88635] 操作1-1 2015-08-12 14:28:08.277 GCDTest[2248:88635] 操作1-2 2015-08-12 14:28:08.277 GCDTest[2248:88635] 操作2-0 2015-08-12 14:28:08.277 GCDTest[2248:88635] 操作2-1 2015-08-12 14:28:08.277 GCDTest[2248:88635] 操作2-2 2015-08-12 14:28:08.277 GCDTest[2248:88635] 操作3-0 2015-08-12 14:28:08.277 GCDTest[2248:88635] 操作3-1 2015-08-12 14:28:08.278 GCDTest[2248:88635] 操作3-2 2015-08-12 14:28:08.286 GCDTest[2248:88609] 更新UI

Main Dispatch Queue and Global Dispatch Queue

Main Dispatch Queue

  /*
  dispatch_get_main_queue
 (1)main queue 是一中serial queue,task是放在主线程的Runloop中执行的;
 (2)一些UI的更新操作需要放在主线程中,使用main queue是比较简单的
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();

global Dispatch Queue

 /*
   dispatch_get_global_queue
 (1)global queue 是一种concurrent queue,可以通过设置queue的priority指定执行的优先级;
 */
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  

3.主线程下死锁的爆发

为了更加好地运用GCD,要求领悟以下的有关线程和产出的定义。

1.1.2 GCD(Grand Central Dispatch)

在iOS和OS
X中落实异步实施任务(二十三十二线程管理)的技术之一。无需手动管理线程的生命周期,作用强大、使用灵活,能知足你对二十多线程管理的富有须求。
例如:

dispatch_async(queue, ^{
//在此处编写需要副线程处理的代码(后台执行)
    dispatch_async(dispatch_get_main_queue( ), ^{
        //反馈到主线程,处理副线程执行完成的结果(反馈到主线程执行)
    });
});

使用GCD代替同步锁

在支付中,借使有四个线程推行同一代码,恐怕会出现存的标题,而解决方案正是给代码加多同步锁。在GCD出现之前,能够选择@synchronized给object创设一个锁,这种办法很轻便选用,不过滥用会导致代码作用低下。而利用GCD能够以更简便、越来越高效的格局给代码加锁。例如在setter和getter中:

- (NSString *)aString { __block NSString *str; dispatch_sync(_myQueue, ^{ str = _aString; }); return str;} - setAString:(NSString *)aString { dispatch_barrier_async(_myQueue, ^{ _aString = aString; });}

其中_myQueue是选取本身创办的面世队列;在getter方法里将操作归入_myQueue里同步试行,能够保障收获格局在操作实行到位后本领重新被利用;而dispatch_barrier_async可以将_myQueue阻塞,并在操作推行到位后再裁撤阻塞,那样能够保证在进行设置格局时不能够执行获取格局。

dispatch_set_target_queue

 /*
 dispatch_set_target_queue的第一个参数是指定要变更优先级的队列;指定与要使用优先级相同优先级的队列为第二个参数
 */
dispatch_queue_t serialqueue1 = dispatch_queue_create("serialqueue1", NULL);
dispatch_queue_t serialqueue2 = dispatch_queue_create("serialqueue2", NULL);
dispatch_set_target_queue(serialqueue2, serialqueue1);
/*  
/*
 主线程,是一个系统自带的串行线程,往主线程添加任务,则需要等当前任务完成,即viewDidLoad方法走完,所以这里Log是后于直接Log的
 死锁:在主线程中同步给主线程添加任务,则产生死锁
 dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"异步添加任务到主线程:%@", [NSThread currentThread]);
 });
 */
 dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"异步添加任务到主线程:%@", [NSThread currentThread]);
});
NSLog(@"直接在主线程中执行:%@", [NSThread currentThread]);

串行 vs 并发(Concurrent)

那三个词都是形容当实行任务时是还是不是需求考虑其余任务。

串行:任务只好多个随之四个地试行出现:同不时候内,五个职分能够是同期实行的

1.2线程与经过

行使GCD落成单例方式

选用GCD能够更简短的实现单例形式,消除方法正是dispatch_once。具体用法就是:

static GCDTest *test; +sharedInstance { static dispatch_once_t once; dispatch_once(&once, ^{ test = [[GCDTest alloc] init]; }); return test;}

因为老是调用时都亟需利用同一的dispatch_once_t,所以须要注明为static。使用dispatch_once能够确认保证线程安全,况兼简化代码。使用dispatch_once也更加快速,它并未有选取重量级的一块机制,而是使用“原子访谈”(atomic
access)来询问dispatch_once_t来剖断其所对应的代码是不是已实行过。GCD的从头到尾的经过与用法远远不仅仅这么些,有野趣的能够在开拓者文书档案中询问。

dispatch_after

/*
  延迟若干时间处理某一个Task,只是追加task到某一个队列,并不一定立即执行task
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
    NSLog(@"wait at least three seconds!!");
});

4.Object-c SDK自带的4个全局并行队列

任务

可以省略地认为职分就是闭包。实际上,也得以经过函数指针来行使GCD,但大许多情况下会比较麻烦。

闭包就是一段能够被积存并传值的可调用代码块。

1.2.1 线程

一条无分叉路线的、线性的、需求CPU分配二个主导去施行的吩咐。

Tips:在iOS和OS
X中,每一种线程系统都会分配八个RunLoop对象(供给手动获取),该对象能够达成循环推行该线程。

dispatch Group

dispatch group
的面世能够缓慢解决四个并发task实施后能接受通告再实行别的任务操作的须求;

  /*
  1; 如果使用 serial queue 所有的task执行完毕后在执行done task
  2:如果使用 concurrent queue 所有的task执行后没办法 执行行done task 就需要 dispatch_group
 */
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
//
dispatch_group_async(group, queue, ^{
    NSLog(@"blok1");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok2");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok3");
});
dispatch_group_async(group, queue, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"blok4");
});
// 监听group 中的task 是否已经全部执行完成
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"done!!");
});
//   dispatch_group_wait会hold住当前线程直到所有task执行完毕
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

NSLog(@"all finish!!!!");

三个互连网乞请施行操作完结在施行下一步操作的供给如何贯彻?

 // 多个网络请求完成后再做新的任务
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //网络请求操作1
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //网络请求操作2
        dispatch_group_leave(group);
    });
/*
 系统自带的4个全局线程(并行),通过以下4个宏设置线程优先级
 #define DISPATCH_QUEUE_PRIORITY_HIGH 2
 #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
 #define DISPATCH_QUEUE_PRIORITY_LOW (-2)
 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
 优先级高的先执行,但是执行完的速度并不一定
 同一优先级的队列中的任务,执行顺序不定
 */
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSLog(@"start_low_1");
    NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSLog(@"start_low_2");
    NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    NSLog(@"start_low_3");
    NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSLog(@"start_default");
    NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSLog(@"start_high");
    NSLog(@"%@", [NSThread currentThread]);
});

同步(Synchronous) vs 异步(Asychronous)

那八个词是用来形容,被调用的函数在哪一天将调控权重临给调用者。

联手:被调用的函数只会在推行完才将调整权给回调用者。异步:被调用的函数会马上将调整权再次来到给调用者,不管函数是或不是实施完。由此异步函数不会堵塞当前经过。

举例说以下代码:同步

override func viewDidLoad() { super.viewDidLoad() dispatch_sync(dispatch_get_global_queue( Int(QOS_CLASS_USER_INTERACTIVE.value), 0)) { NSLog("First Log") } NSLog("Second Log")}

图片 1dispatch_sync_in_action_swift.gif

职责viewDidLoad会暂停等同步sync里面包车型客车天职实行完再持续下一行代码。

异步

override func viewDidLoad() { super.viewDidLoad() dispatch_async(dispatch_get_global_queue( Int(QOS_CLASS_USER_INTERACTIVE.value), 0)) { NSLog("First Log") } NSLog("Second Log")}

图片 2dispatch_async_in_action_swift.gif

如图,职务viewDidLoad不等待异步asyn里面包车型地铁代码职务施行完,就直接开首下一行代码

1.2.2 进程

出现实施的前后相继在实行进度中分配和管理财富的中央单位,是三个动态概念,竟争Computer系统能源的主导单位。

dispatch_barrier_async

多线程操作发生的贰个标题就是数量能源的竞争,读写操作怎么样能担保线程安全性;dispatch_barrier_async提供了缓和方案

 /*
   使用concurrent dispatch queue 和 dispatch barrier async 函数可实现高效率的数据库访问和文件读取
 */
dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"task1forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task2forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task3forReading!");
});
dispatch_barrier_async(queue, ^{
    // 此taskforWriting 会等到加入concurrentQueue中的task执行完毕后,执行taskforWriting,等到该taskforWriting执行完毕后在执行 concurrentQueue中的task
    NSLog(@"taskforWriting!");
});
dispatch_async(queue, ^{
    NSLog(@"task4forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task5forReading!");
});

5.自定义队列

高危代码段(Critical Section)

那是一段不能够并发实践的代码。也正是无法被八个线程同一时候实施。比方:这段代码是因为修改分享的能源比方,只要十二线程运维会即刻崩溃。

1.2.3 两个的涉嫌

  • 系统一分配配三个进度去管理贰个顺序的运作。
  • 前后相继中也许涉及三个或多个线程同一时候推行,此时就须要进度实时分配CPU、内部存款和储蓄器等计算机财富。

Tips:在微型Computer管理多线程时,一时会由此定期切换实践职分(每隔一定时期,来回切换推行的职分),来完结CPU单个主旨同不经常候举办八个线程。

Tips:从切换指标路线专项使用的内存块中,复原CPU寄放器等音信,继续实践切换路线的CPU命令列,这被称之为“上下文切换”。

dispatch_sync

/*
dispatch_sync 函数意味着等待;它要等待task执行完毕后再做返回
*/
//使用dispatch_sync 容易造成死锁
//在主线程中执行以下源代码会造成死锁
/*
  main_queue 是一个serialQueue ,使用dispatch_sync将task加入到mainqueue中task会等待mainqueue中的任务执行完成,而mainqueue又要等待task完成,由此造成了死锁;
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{
    NSLog(@"hello dispatch_sync!");
});
//>2在主线程中执行以下源代码也会造成死锁
dispatch_async(main_queue, ^{
   dispatch_sync(main_queue, ^{
       NSLog(@"hello!!");
   });
});
/*
 自己创建线程队列,一般不创建并行的,因为系统自带的已经够了
 串行队列-异步执行:任务会根据添加顺序执行,但是不阻碍下面的其他代码执行
 串行队列-同步执行:基本和直接在主线程中写代码没什么区别
 */
dispatch_queue_t my_queue = dispatch_queue_create("my_queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(my_queue, ^{
    NSLog(@"start_my_1");
    NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(my_queue, ^{
    NSLog(@"start_my_2");
    NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    NSLog(@"start_high_2");
    NSLog(@"%@", [NSThread currentThread]);
});

线程安全

能被多个线程相同的时候试行的能源

1.3 线程队列

dispatch_apply

  NSMutableArray* tempArr  = [@[@"key1",@"key2",@"key3",@"key4",@"key5"] mutableCopy];
   // 1 按照指定的次数将指定的Block追加到指定的Dispatch_Queue中,并等待全部处理执行结束
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply([tempArr count], queue, ^(size_t index) {
        // 要做数据更新操作
        NSLog(@"%d",index);
    });
    NSLog(@"task done");
    /*
     1 对数组进行循环遍历的方法
       1》 for循环
       2》 block
       3》 dispatch_apply
      2 dispatch_apply 要等待结束,最好和 dispatch_async函数混合使用
     */

6.设置队列优先级,仅能设置自定义队列

财富竞争(race condition)

图片 3race-condition@2x-8b11b31d.png

如图,有多个变量存款和储蓄着17,然后线程A读取变量得到17,线程B也读取了这么些变量。多少个线程都举办了加1运算得,并写入18都变量。进而致使了崩溃。那便是race
condition,四线程使用分享能源,而从未保险别的线程是早就甘休使用分享能源。

1.3.1 并行

  • 对n个须求相同的时间推行(不等待以往实施中的任务管理实现,直接施行下一义务)的职务创设线程队列,是一种四线程技巧。
  • 虽说可以加上八个并行线程队列,但在(但不光限于)iOS和OS
    X系统下,系统会基于当下线程数量、Computer质量等因素,来推断当前内需同期执行的天职位数量量(正是说,不管你弹指间拉长多少个相互的职分,同期试行的任务数量是有上限的)。

挂起队列和进行队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//挂起队列
dispatch_suspend(queue);
//恢复指定队列
dispatch_resume(queue);  
/*
 dispatch_set_target_queue
 把我们的队列添加到全局队列中执行,则我们队列的优先级就会和全局队列一样
 通常用这种方式来改变我们自己创建的队列的优先级
 */
dispatch_set_target_queue(my_queue, dispatch_get_global_queue(0, 0));

相互排除(Mutual Exclusion)

图片 4locking@2x-f425450b.png

如图,使用锁对线程正在利用的分享能源举行锁定,当分享财富使用完后。另外线程手艺使用那一个分享变量。那样就能够防止race
condition但会导致死锁。

1.3.2 串行

  • 对n个供给各样施行(等待现在实践中的任务管理终结后,才实行下一职分)的天职创立线程队列,是一种八线程才干。
  • 异步的拉长过多并行线程队列,系统会为种种队列创造二个线程,何况不会有数量限制。
  • 故此,如若过多创立串行队列,就能消耗多量系统能源,减少质量。

dispatch_Semaphore

 // 1  向数组中增加对象由于内存错误导致异常的概率会很高
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray* mutable_arr =[NSMutableArray array];
for(int i = 0;i<100000;++i)
{
   dispatch_async(queue, ^{
       [mutable_arr addObject:[NSNumber numberWithInt:i]];
   });
}


// 2 使用dispatch_semaphore进行更细粒度的线程管理
dispatch_queue_t global_queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
  生成Dispatch Semahpore
  dispatch_Semahpore 的计数初始值设定为“1”
  这样能保证访问NSMutableArray类对象的线程,同时只有1个
 */
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray* array =[NSMutableArray array];
for(int i = 0;i<10000;i++)
{
    dispatch_async(global_queue, ^{
        /*
         等待Dispatch Semaphore
         直到Dispatch Semphore的计数值达到大于等于1;
         */
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        /*
         由于dispatch Semaphore 的计数值达到大于等于1
         所以将Dispatch semaphore 的计数值减去1
         dispatch_semaphore_wait 函数执行返回
         执行到此 dispatch Semaphore的计数值恒为“0”
         */

        [array addObject:[NSNumber numberWithInt:i]];

        /*
         排他控制处理结束,所以通过dispatch_semaphore_signal函数 将
         Dispatch Semaphore的计数值加1
         如果有通过dispatch_semaphore_wait 函数 等待dispatch Semaphore 的计数值增加的线程 就由最先等待的线程执行
         */
        dispatch_semaphore_signal(semaphore);

    });
}

7.GCD中的布告调用Api

死锁

图片 5dead-lock@2x-b45f0acd.png

七个线程等待着互相的做到而陷入的困境称为死锁。

void swap{ lock; lock; int a = A; int b = B; A = b; B = a; unlock; unlock;}swap; // 线程 thread 1swap; // 线程 thread 2

结果就能导致X被线程1锁住,Y被线程2锁住。而线程1又不能够使用Y直到线程2解锁,同理,线程2也不可能使用X。那正是死锁,相互等待。

1.3.3 并行与产出

出现,是一种现象(能够说是一个标题);
而相互,是一种三十二线程的技巧(能够说是赶尽杀绝难点的方案)。
例如,并发就好像有n个人排队购票,而相互,则疑似同一时候开了m个买票窗口消除n个人同有的时候间定票的耗时难点。

dispatch_once

担保应用程序中只举办贰次钦赐管理的API

 +(instancetype)shareInstance
    {
        static ViewController* _vc;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _vc =[[self alloc] init];
        });
        return _vc;
    }
/*
 group和notify
 1.由Log可见,over都是在1,2之后的确实起到了通知的作用
 2.over2并没有等待两个异步请求完成就已经调用,这是因为请求本身是异步的,在调用后直接返回了,所以dispatch_group_async认为该任务已经执行完,所以无作用
 3.要把一个方法或函数作为任务添加到组中等待通知,应该使用dispatch_group_enter()和dispatch_group_leave()
 */
// 1
dispatch_queue_t queue = dispatch_queue_create("my1", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
    NSLog(@"1");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"2");
});
dispatch_group_notify(group, queue, ^{
    NSLog(@"over");
});

// 2
dispatch_queue_t queue2 = dispatch_queue_create("my2", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group2 = dispatch_group_create();
dispatch_group_async(group2, queue2, ^{
    [self request1:^{

    }];
});
dispatch_group_async(group2, queue2, ^{
    [self request2:^{

    }];
});
dispatch_group_notify(group2, queue2, ^{
    NSLog(@"over2");
});

// 3
dispatch_queue_t queue3 = dispatch_queue_create("my3", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group3 = dispatch_group_create();
dispatch_group_enter(group3);
[self request1:^{
    dispatch_group_leave(group3);
}];

dispatch_group_enter(group3);
[self request2:^{
    dispatch_group_leave(group3);
}];
dispatch_group_notify(group3, queue3, ^{
    NSLog(@"over3");
});

先行顺序颠倒(Priority Inversion)

预先顺序颠倒难点,是由低权限义务的不通着高权力职分的实行。进而让种种颠倒。

图片 6priority-inversion@2x-72e6760c.png

如若低权限的线程和高权力的线程使用分享能源。本应有,低权限的线程职务使用完分享能源后高权力的线程职责就能够未有延迟地实行。

但由于一始发高权力的线程因为低线程的锁而遇到阻塞。所以就给了空子中权限的线程任务,因为未来高权力受阻,所以中权限的线程任务是权力最高的,所以中权限义务中断低权限的线程职务的奉行。进而让低线程的锁解不开,高线程任务也就延迟奉行。进而优先顺序颠倒。

就此在运用GCD的时候,最棒将八线程的职务实施优先权限保持一致。

1.4 同步与异步

8.阻塞线程

队列

GCD提供dispatch
queue来管理提交的天职。这么些队列管理你提交给GCD的天职并且依据FIFO的一一实践。

dispatch queue都以线程安全的所以能够在多少个线程里还要利用它们。

图片 7Serial-Queue-Swift-480×272.png

串行队列只好贰回实践一个职责。如图,串行队列会二个紧挨着一个地实施任务,就是贰个说尽另贰个本事开首。

图片 8Concurrent-Queue-Swift-480×272.png

并发队列里的天职是以踏向队列的逐条实践的,但你不鲜明职务哪一天实现,几时伊始下二个职责。那有赖于GCD。

如图:职务0,1,2,3的开头是有种种的。但同期内可以有两个职责运转。

1.4.1 同步

  • 一块的,将要求推行的职务,追加到内定线程队列中。
  • 当必要实行的职分,同步追加到执行线程队列时,内定线程队列必得暂停,等待该职务施行完结,才具一而再往下实行。
  • 就此同步线程,轻易迷惑死锁难题。
/*
 dispatch_barrier_async
 dispatch_barrier_async传的队列参数必须是用户自己创建的,否则没用
 当用户想要先完成任务1,2,中途要等待任务3完成后,才能开始4,5,其中12,45是并发的
 dispatch_barrier_async和dispatch_barrier_sync的共同点在于都会阻挡在dispatch_barrier之后添加的任务,并延时调用(等待它之前的任务回调完成),不同点在于async是不阻挡主线程的,而sync是阻挡主线程的
 */

dispatch_queue_t barrier_queue = dispatch_queue_create("zk_barrier_queue", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_1");
});
dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_2");
});
dispatch_barrier_async(barrier_queue, ^{
    NSLog(@"barrier_3");
});
NSLog(@"aa");
dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_4");
});
dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_5");
});

dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_1_1");
});
dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_2_2");
});
dispatch_barrier_sync(barrier_queue, ^{
    NSLog(@"barrier_3_3");
});
NSLog(@"bb");
dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_4_4");
});
dispatch_async(barrier_queue, ^{
    NSLog(@"barrier_5_5");
});

队列类型(Queue Types)

首先,系统提供了个特效的行列main queue,

main
queue是串行队列,所以三回只可以执行叁个义务。但以此队列是独一贰个能用来更新UI和出殡和埋葬公告的行列。

系统也同一时候提供了多少个并发队列。那一个队列与自家的QOS品级有关,使得GCD可以操纵优先级。

  • QOS_CLASS_USER_INTERACTIVE
  • QOS_CLASS_USER_INITIATED
  • QOS_CLASS_UTILITY
  • QOS_CLASS_BACKGROUND

Apples的API也会调用这几个global dispatch
queues,所以你加多的职分不会是队列里独一的天职。

而外上述5种队列外,你还是可以创立队列。

1.4.2 异步

  • 非同步的,将索要推行的天职,追加到钦命线程队列中。
  • 将急需施行的职分,非同步的增加到钦点线程队列后,会产生叁个新的线程队列,而因为非同步增添,所以系统会新生成n个线程来实践该新的线程队列。
  • 因为奉行时间不一致台,所以轻便引发多少竞争难题。

9.延迟调用

防止read write问题

比如在贰个单例里有有如下属性,读和写

private var _photos: [Photo] = []//writefunc addPhoto(photo: Photo) { _photos.append}//readvar photos: [Photo] { return _photos}

能够保障线程安全的独有用let定义的。而数组,字典等用var定义的都不是线程安全的。

而地点的read和write都对变量数组实行转移使用。所以线程不安全。那怎么本事使其线程安全啊?

利用dispatch barriers实施read write lock

图片 9Dispatch-Barrier-Swift-480×272.png

如图,dispatch barriers 能确定保障在它在此之前的task都试行完,在它之后的task
直到它成功前都无法实施也正是说在那个task在它施行的时刻独占所在队列。

那正是说修改后的read write如下:

private var _photos: [Photo] = []//创建自定义并发队列private let concurrentPhotoQueue = dispatch_queue_create( "com.raywenderlich.GooglyPuff.photoQueue", DISPATCH_QUEUE_CONCURRENT) //writefunc addPhoto(photo: Photo) { dispatch_barrier_async(concurrentPhotoQueue) { self._photos.append }}//readvar photos: [Photo] { var photosCopy: [Photo]! dispatch_sync(concurrentPhotoQueue) { photosCopy = self._photos } return photosCopy}

write:

选用dispatch barriers,为何制造自定义并发队列?

因为能够运用dispatch barriers有以下二种队列:

  • 自定义串行队列,因为串行队列本来正是叁个职务二个职务地实践,所以用了等于没用。
  • 大局队列(Global Concurrent
    Queue),因为全局队列,Apples的API也使用,所以当使用dispatch
    barriers时,会堵塞队列。不建议利用
  • 自定义并发队列,只要并发队列里使用的是能源线程安全的。所以相比较提议。

read:应用sync而且跟write同一并发队列,因为这确定保证read和write是有各种的。进而防止八线程的读写难题。

参谋链接objc.io关于二十八线程或者导致的主题素材作品raywenderlich关于GCD使用的篇章

1.5 三十二线程难点

即便应用八线程编制程序能够确定保障客户分界面包车型地铁响应,但倘若使用不当轻巧发生各样编制程序难点。以下是大范围的二种:

/*
 dispatch_after
 延迟调用,一旦开始,就无法停下,一般只用在主队列中
 */
dispatch_after(dispatch_time(dispatch_walltime(NULL, 0), 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    NSLog(@"dispatch_after");
});
dispatch_after(dispatch_time(0, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    NSLog(@"dispatch_after2");
});
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^{
    NSLog(@"dispatch_after2");
});

1.5.1 数据竞争

多个线程同临时间施行时,更新同样的能源,导致数据的分化等。

10.遍历

1.5.2 死锁

多少个线程同一时候试行时,若是互相之间限制实施,会招致多少个线程相互持续等待而使程序无法继续实施。

/*
 dispatch_apply
 无序遍历,会开启多个线程,但会阻碍主线程的运行
 */
NSArray *array = @[@1, @2, @3, @4, @5];
dispatch_apply(array.count, dispatch_get_global_queue(0, 0), ^(size_t index) {

    NSLog(@"%@---%@", [NSThread currentThread], array[index]);
});
NSLog(@"主线程end");

1.5.3 大量消耗财富

动用过八线程会开销多量Computer财富。

2 iOS和OS X中GCD的API

2.1 线程队列(Dispatch Queue)

Dispatch Queue,施行管理的等候队列。
开采者只需将要求实行的天职增加到合适的线程队列,就可以兑现十二线程编制程序。

2.1.1并行队列(DISPATCH_QUEUE_CONCURRENT)

先进先出(FIFO
First-In-First-Out)的逐个施行处理,并且不等待未来试行中的管理实现。
其他释义同1.3.1。

2.1.2串行队列(DISPATCH_QUEUE_SERIAL)

先进先出(FIFO
First-In-First-Out)的一一实施管理,何况等待今后实践中的管理实现。
别的释义同1.3.2。

2.2 创建线程队列(dispatch_queue_create函数与dispatch_queue_t类型变量)

2.2.1释义

dispatch_queue_create是依据参数类型,创造线程队列的函数。
dispatch_queue_t为dispatch_queue_create函数的回来值类型,线程队列类型。

2.2.2 用法:

dispatch_queue_t testQueue = dispatch_queue_create("com.Test.GCD.testQueue",DISPATCH_QUEUE_CONCURRENT); 
  • 参数一,生成线程的称号(推荐使用程序ID的逆序全程域名+变量名称);
  • 参数二,生成线程类型,串行为DISPATCH_QUEUE_SE景逸SUVIAL(或设为NULL),并行钦命为DISPATCH_QUEUE_CONCURRENT。
  • 返回值,dispatch_queue_t类型线程队列变量。

2.2.3 注意

在iOS 6.0
SDK此前版本,GCD中有着create的成立的对象,都亟待用dispatch_retain、dispatch_release来扩充内部存款和储蓄器管理。而iOS
6.0 SDK现在的本子,只要展开ARC就无需对GCD的靶子进行内部存款和储蓄器管理。

2.3 异步追加(dispatch_async函数)

2.3.1释义

  • 异步追加线程队列,线程队列遵照追加的顺序(先进先出)实施管理。
  • 任何释义同1.4.1。
  • 将索要异步实行的代码写在Block中, Block会异步的增加到线程队列中。。
  • Block的开始和结果,能够参谋此文

2.3.2 用法

//创建一个并行队列testQueue
dispatch_queue_t testQueue = dispatch_queue_create("com.Test.GCD.testQueue",DISPATCH_QUEUE_CONCURRENT);

//将Block中需要执行的任务,异步的追加到testQueue中
dispatch_async(testQueue, ^{
    //需要执行的任务
}); 

2.4 主线程(Main Dispatch Queue)

2.4.1释义

当叁个主次运转时,就有二个进程被操作系统(OS)创立,与此同有时候叁个线程也即刻运营,该线程平常可以称作程序的主线程(Main
Thread),因为它是程序开首时就实践的,假如您需求又创制线程,那么创设的线程正是以此主线程的子线程。(此段释义来自百度健全)

在iOS中,全体追加到主线程的拍卖,都以在主线程的RunLoop中实践。
当在后台实行的职责成功后,倘使急需将结果在UI中浮现,此时则需求调用主线程来更新顾客分界面。

2.4.2 用法

dispatch_queue_t testQueue = dispatch_queue_create("com.Test.GCD.testQueue",DISPATCH_QUEUE_CONCURRENT);

dispatch_async(testQueue, ^{
    //需要执行的任务
    dispatch_queue_async(dispatch_get_main_queue(), ^{
        //将结果反馈到主线程,例如更新用户界面
    });
}); 

2.5 全局队列(Global Dispatch Queue)

2.5.1释义

系统提供的并行线程队列(DISPATCH_QUEUE_CONCU昂CoraRENT),不要求极其生成(推荐应用)。
依照已赢得并行队列的优先级,系统会活动推断试行的先后,但鉴于举办时间长度的不明确性,并不可能担保完全遵照事先级来实行。

2.5.2 Global Dispatch Queue的4个优先级:

  • DISPATCH_QUEUE_PRIORITY_HIGH,最高优先级;
  • DISPATCH_QUEUE_PRIORITY_DEFAULT,私下认可优先级;
  • DISPATCH_QUEUE_PRIORITY_LOW,低优先级;
  • DISPATCH_QUEUE_PRIORITY_BACKGROUND,后台优先级(在高高的优先级队列和已经扩充的后台优先级队列之后,施行)。

2.5.3 用法:

dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

2.6 优先级设定(dispatch_set_target_queue函数)

2.6.1释义

dispatch_queue_create函数创制的线程队列,不论是相互还是串行,其优先级皆为暗中认可优先级。
设若必要退换线程队列的优先级,须求用到dispatch_set_target_queue函数。

2.6.2 用法

//创建串行线程队列testQueue
dispatch_queue_t testQueue = dispatch_queue_create(“com.Test.GCD.testQueue”, NULL); 

//获取后台优先级的全局队列
dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

//将testQueue的优先级设定成与testGlobalQueue相同
dispatch_set_target_queue(testQueue, testGlobalQueue);
  • 参数一:改换值,供给改换优先级的线程队列;
  • 参数二:目的值,将参数一的先行级退换成与参数二一模二样。

2.5.3 注意

  • 参数一不能够为Main Dispatch Queue或Global Dispatch Queue。
  • 参数二纵然为串行线程队列,那么参数一与参数二将串行实施职责(原来俩货是相互的,但经过dispatch_set_target_queue之后就成为串行,何况参数二的队列优先实行)。

2.7 线程计时(dispatch_after函数与dispatch_time_t类型变量)

2.7.1释义

dispatch_after函数能够将Block职责,在指定时间过后推行。
dispatch_time_t类型声圣元(Synutra)个时刻项目变量。

2.7.2 用法:

//创建一个dispatch_time_t类型的时长变量
dispatch_time_t testTime = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);

//在主线程中,延后最少3秒执行Block中的任务(为什么最少3秒,后面会讲)
dispatch_after(testTime, dispatch_get_main_queue(), ^{
    NSLog(@”延后最少3秒,再执行!”);
});
  • dispatch_time函数用来创制三个时光,重返贰个以参数一为发轫时间,经过参数二安装的、以飞秒为单位的时间长度之后的二个dispatch_time_t时间类型变量(有一些绕口,轻松说正是参数一的年月增加参数二的时间长度,得出的值)。
  • 获取dispatc_time_t类型变量,还会有一种格局,用dispatch_walltime函数来收获,感兴趣的朋友能够活动查阅资料。
  • dispatch_after函数的用法,一览掌握。

2.7.3 注意

  • dispatch_after函数并非是在testTime后就立即实践管理,而是在testTime追加Block到线程队列中。假诺是在主线程,则会追加到RunLoop中。
  • 故此Block的实践时间是超越等于testTime,且小于RunLoop循环间隔时间长度+
    testTime。

2.8 线程群(Dispatch Group)

2.8.1释义

当四个职分,须要等互相的四个任务总体实行完结之后实践该职分。那时就须要用到线程群(Dispatch
Group)来减轻那么些主题材料。能够将多少个并行任务都加上到线程群中,等线程群中的全数任务都施行达成后,再钦定去实行该职责。

2.8.2 用法

dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//创建线程群
dispatch_group_t testGroup = dispatch_group_create();

//追加任务到线程队列,再讲线程队列追加到线程群
dispatch_group_async(testGroup, testGlobalQueue, ^{NSLog(@”并行任务一”);}); 
dispatch_group_async(testGroup, testGlobalQueue, ^{NSLog(@”并行任务二”);});
dispatch_group_async(testGroup, testGlobalQueue, ^{NSLog(@”并行任务三”);});

//当线程群中的任务都执行完毕,将所有结果反馈到对应线程
dispatch_group_notify(testGroup, dispatch_get_main_queue(), ^{
    NSLog(@”反馈以上三个任务的结果”);
});

//该函数不对结果做处理,仅等待线程群执行结束
//dispatch_group_wait(testGroup, DISPATCH_TIME_FOREVER);

实行结果:

并行任务二
并行任务三
并行职务一
反映以上多个任务的结果

2.8.3 注意

  • 线程群中能够追加并行队列,也得以追加串行队列,只要在线程群中的职务总体实施实现,dispatch_group_notify函数就能够检测到。
  • dispatch_group_notify函数能够在线程群中的职务总体实行达成之后,做出相应的申报;也得以用dispatch_group_wait函数仅等待全体职务实行完成,而不作管理。

2.9 线程等待(dispatch_barrier_async函数)

2.8.1 释义

当程序执行到dispatch_barrier_async函数时,会等待从前的线程队列中的职务施行完成,然后暂停线程队列,当dispatch_barrier_async函数中Block试行达成,再持续施行线程队列的天职。

2.9.2 用法:

dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(testGlobalQueue, ^{NSLog(@”并行任务一”);}); 
dispatch_async(testGlobalQueue, ^{NSLog(@”并行任务二”);}); 
dispatch_async(testGlobalQueue, ^{NSLog(@”并行任务三”);}); 

dispatch_barrier_asyn (testGlobalQueue, ^{NSLog(@”任务一、二、三已经执行完成,任务四、五、六还未开始执行”);}); 

dispatch_async(testGlobalQueue, ^{NSLog(@”并行任务四”);}); 
dispatch_async(testGlobalQueue, ^{NSLog(@”并行任务五”);}); 
dispatch_async(testGlobalQueue, ^{NSLog(@”并行任务六”);}); 

2.9.3 注意

当多少个并行职责供给对同样数据进行写入操作,而且事后又有多个并行任务要求对该多少实行读取操作时。或然出于同时对该数据开展操作,而形成数据竞争难点;也很有相当大概率后边施行的天职读取到的数量并不雷同难点。将写入操作聚集到dispatch_barrier_async函数处理,就能够消除那样的标题。

2.10 联名追加(dispatch_sync)

2.10.1释义

共同追加线程队列,线程队列根据追加的逐个(先进先出)奉行拍卖。
别的释义同1.4.1。

2.10.2 用法:

dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_sync(testGlobalQueue, ^{
    //需要执行的任务
}); 

2.10.3 注意

  • 若果调用dispatch_sync函数,那么在Block管理终结以前,函数不会回到。由此轻巧导致线程死锁。

例如:

dispatch_queue_t testQueue = dispatch_queue_create(“com.Test.GCD.testQueue”, NULL);


    dispatch_sync(testQueue, ^{
        NSLog(@”会执行!”);

    //由于testQueue串行队列,所以Block等待当前线程队列执行完毕,在执行Block
    //而由于dispatch_sync同步追加,会让当前线程队列等待Block执行完毕,再恢复
    //由此相互等待,则造成线程死锁
    dispatch_sync(testQueue, ^{
        NSLog(@”此段代码不会执行!”);
    }); 
}); 
  • 是因为主线程(Main Dispatch
    Queue)也是一同线程,所以地点的testQueue换到主线程也会挑起死锁。

2.11 数十次扩大(dispatch_apply函数)

2.11.1 释义

该函数按钦点的次数将点名的Block追加到钦定的线程队列中,并等候全体管理实践完成

2.11.2 用法

dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(10, testGlobalQueue, ^(size_t index) {
    NSLog(@”%zu”,index);
});
NSLog(@”完成!”);

2.12 线程挂起(dispatch_suspend函数)与线程恢复生机(dispatch_resume函数)

2.12.1 释义

dispatch_suspend函数能够暂停钦定线程的实施。
dispatch_resume函数复苏实践线程的施行。

2.12.2 用法

//暂停
dispatch_suspend(testQueue);
//恢复
dispatch_resume(testQueue);

2.13 线程计数(Dispatch Semaphore)

2.13.1 释义

Dispatch
Semaphore是装有计数的信号,该计数是八线程编制程序中的计数类型实信号。
当钦定线程计数为0时则暂停;大于等于1时,减去1而苏醒。

2.13.2 用法

dispatch_queue_t testGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray * array = [[NSMutableArray alloc] init];

//创建一个初始值为1的线程计数
dispatch_semaphore_t testSemaphore = dispatch_semaphore_create(1);

for (int i = 0; i < 1000; ++i) {

    dispatch_async(testGlobalQueue, ^{

        //计数-1,暂停线程,直到线程计数大于等于1
        dispatch_semaphore_wait(testSemaphore, DISPATCH_TIME_FOREVER);

        //线程安全,不存在数据竞争
        [array addObject:[NSNumber numberWithInt:i]];

        //计数+1,恢复线程
        dispatch_semaphore_signal(testSemaphore);
    });
}

2.14 单例形式(dispatch_once函数)

2.14.1 释义

通过单例方式能够保险系统中几个类唯有八个实例并且该实例易于外部访问,进而方便对实例个数的调控并节约系统财富。假若期待在系统中有些类的指标只可以存在二个,单例形式是最棒的缓慢解决方案。(此段释义来自百度健全)
dispatch_once函数能够保险在应用程序试行中,只举办叁遍内定职责。

2.14.2 用法

static dispatch_once_t once;
dispatch_once(&once, ^{
    //需要进行的处理
});

2.14.3 注意

上述用法仅为单例方式的内部一种写法,其余写法及一语破的的钻探,请自行查阅资料,这里就不实行了。

参考
《Objective-C高档编制程序
iOS与OS
X多线程和内部存款和储蓄器管理》【日】Kazuki Sakamoto 汤姆ohiko Furumoto 著 黎华

《关于iOS二十四线程,你看自身就够了》http://www.jianshu.com/p/0b0d9b1f1f19

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图