多线程编程(GCD)

多线程

Mac、iPhone的操作系统OS X、iOS根据用户的指示启动应用程序后,首先便将包含在应用程序中的CPU命令列配置到内存中。CPU从应用程序知道的地址开始,一个一个执行CPU命令列。

在OC的if或for语句等控制语句或函数调用的情况下,执行命令列的地址会远离当前的位置(位置迁移)。但是,由于一个CPU一次只能执行一个命令,不能执行某处分开的并列的两个命令,因此通过CPU执行的CPU命令列就好比一条无分叉的大道,其执行不会出现分歧。

通过CPU执行的CPU命令列.png

这里所说的“1个CPU执行的CPU命令列为一条无分叉路径”,即为“线程”

这种无分叉路径不只1条,存在有多条时即为“多线程”。1个CPU核执行多条不同路径上的不同命令。

线程

在多线程中执行CPU命令列.png

OS X和iOS的核心XNU内核在发生操作系统事件时(如每隔一定时间,唤起系统调用等情况)会切换执行路径。例如CPU的寄存器等信息保存到各自路径专用的内存块中,从切换目标路径专用的内存块中,复原CPU寄存器等信息,继续执行切换路径的CPU命令列。这被称为“上下文切换

由于使用多线程的程序可以在某个线程和其他线程之间反复多次进行上下文切换,因此看上去就好像1个CPU核能够并列地执行多个线程一样。而且在具有多个CPU核的情况下,就不是“看上去像”了,而是真的提供了多个CPU核并行执行多个线程的技术。

这种利用多线程编程的技术就被称为“多线程编程

但是,多线程编程实际上是一种易发生各种问题的编程技术。比如多个线程更新相同资源会导致数据的不一致(数据竞争)、停止等待事件的线程会导致多个线程相互等待(死锁)、使用太多线程会消耗大量内存等。

多线程编程导致的问题

*多线程技术

多线程简单来说是指一个进程中开启多个线程,多个线程并发执行(同时执行,并行)的技术。例如一个进程中开启三个线程同时执行3个不同任务:

多线程并行操作

*多线程原理

对于单核CPU而言,同一时间只能执行一个线程,只能允许一个线程工作。多线程并发是指在一个进程中开启了多个线程,CPU在各个线程之间来回调度。当CPU的调度时间足够快时就产生了多线程并发执行的效果。

*多线程技术的有优点:

1、可以充分利用多核CPU的性能,提供资源的利用率

2、能够提高程序的运行效率,使程序响应更快。

3、能够设置不同任务的执行优先级,

*多线程技术的缺点 (数据竞争、死锁、太多线程导致消耗大量的内存)

1、线程的创建需要CPU的开销,对线程的管理需要额外的CPU开销。线程的使用会为系统带来上下文环境切换带来额外的负担。线程越多,CPU在线程调度管理上的开销就越大,对于移动设备尤甚。

2、线程之间的通信和数据交互复杂。

3、多个线程直接对于资源的使用会导致程序变慢,同时会导致资源的竞争,数据的共享等不安全问题。

。。。

多线程数据安全问题

线程不安全:就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。

线程不安全


线程安全:简单来说就是多个线程同时对共享资源进行访问时,采用了加锁机制,当一个线程访问共享资源,对该资源进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。

线程安全

**线程的几种存在状态

线程几种状态的切换

新建状态(New):当新创建一个线程时,此时线程处在新建状态。程序还没有开始执行线程中的代码。

就绪状态(Runnable):一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start方法创建线程运行的系统资源,这时候线程就处于就绪状态。

运行状态(Running):当线程获得CPU时间后,它才进入运行状态,真正开始执行线程中的代码。

阻塞状态(Blocked):当线程在运行中遇到:1,调用sleep方法;2,线程调用一个在I/O上被阻塞的操作;3,线程等待同步锁;4,线程在等待某个触发条件等几种情况时,线程就处于阻塞状态。 所谓阻塞状态是正在运行的线程没有运行结束,但是不被CPU调度,暂时让出CPU资源,这时其他处于就绪状态的线程就可以获得CPU调度,进入运行状态。

死亡状态(Dead): ** 当线程任务执行完毕或者异常时,线程处于死亡状态。死亡后的线程将不能在执行任务。

iOS中多线程编程的实现方案有一下几种:pthreadNSThreadGCDNSOperation。


GCD

Grand Central Dispatch(牛逼的中枢调度系统),苹果公司利用C语言开发的多线程实现技术,旨在通过充分利用设备的多核处理器以优化提升应用程序的运行。

GCD的使用步骤:

创建任务

将任务存放到队列中(GCD根据队列的FIFO原则自动将队列中的任务取出,放到对应的线程中执行)

GCD中三个重要的概念:

任务,就是需要执行的操作;

队列,就是存放任务的容器,其中队列又被分为并发队列、串行队列两种。

同步函数/异步函数

GCD中队列和函数:

并发队列(Concurrent Dispatch Queue)

允许多个任务并发(同时)执行的队列

//创建一个并发队列,标志为  www.cqut.queue

dispatch_queue_t queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);

串行队列(Serial  Dispatch Queue)

串行队列中的任务只能依次执行

//创建一个串行队列,标志为  serial.queue

dispatch_queue_t queue = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);

同步函数

在当前线程执行任务,不会开启新的线程

//同步函数,传入队列,执行Block中的任务

dispatch_sync(dispatch_queue_t  _Nonnull queue, ^(void)block)

异步函数

可以开启新线程并在其中执行任务

//异步函数,传入队列,执行Block中的任务

dispatch_async(dispatch_queue_t  _Nonnull queue, ^(void)block)

注意:同步/异步决定是否开启线程;并发/串行决定任务的执行方式,允不允许并发。根据函数同步/异步调用和任务放置在并发还是串行队列中我们可以得到下面四种组合:

异步函数 + 并发队列

开启多个子线程同时执行多个任务(任务并行)。

异步函数 + 串行队列

开启一个子线程,任务在该线程中依次执行(任务串行)。

同步函数 + 并发队列

不会开启子线程,此时的队列由于没有子线程支持,失去了并发的能力,任务在当前线程中依次执行(任务串行)。

同步函数 + 串行队列

不会开启子线程,任务在队列中依次执行(任务串行)。

GCD中两个特殊的队列:

dispatch_get_main_queue():主队列

GCD默认创建,只需要使用。该函数返回绑定到主线程的默认串行队列。该队列中执行的任务必定是在主线程中执行的。

dispatch_get_global_queue(long identifier, unsigned long flags):全局并发队列

【参数说明】flags:保留在未来使用,默认传0;

identifier: 分配到队列的项目运行的优先级,优先级由高到低依次为:DISPATCH_QUEUE_PRIORITY_HIGH、DISPATCH_QUEUE_PRIORITY_DEFAULT、DISPATCH_QUEUE_PRIORITY_LOW、DISPATCH_QUEUE_PRIORITY_BACKGROUND,一般我们使用默认的DISPATCH_QUEUE_PRIORITY_DEFAULT就能满足需求

该函数返回

下面一张图简单概括一下关于同步/异步函数和各种队列之间排列组合子线程开启于任务执行情况:

队列与线程.png

由图可知开发中最常用的就是异步函数组合并发和串行队列,

注意】:使用同步函数(sync)向当前串行队列中添加任务会卡住当前队列,导致任务不能正常执行。

GCD中常用的函数

dispatch_barrier_async:在该函数之前的任务必定先执行,在该函数之后的任务后执行(当前队列不能是全局并发队列)。

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {

//并发队列

dispatch_queue_tqueue =dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

//执行下面的异步函数

dispatch_async(queue, ^{

NSLog(@"==1==%@",[NSThreadcurrentThread]);

});

dispatch_barrier_async(queue, ^{

NSLog(@"==barrier==%@",[NSThreadcurrentThread]);

});

dispatch_async(queue, ^{

NSLog(@"==2==%@",[NSThreadcurrentThread]);

});

}

//延时执行

//在主队列的delayInSeconds秒后执行任务

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(delayInSeconds *NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

});

//一次性代码执行

//Block中的代码保证在程序运行中只执行一次,默认是线程安全的

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

NSLog(@"onceToken");

});

快速迭代(遍历)

//全局并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//快速遍历

dispatch_apply(10, queue, ^(size_t index) {

NSLog(@"-%zd-%@",index,[NSThread currentThread]);

});

队列组

//创建队列组

dispatch_group_t group = dispatch_group_create();

//全局并发队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//执行任务一

dispatch_group_async(group, queue, ^{

NSLog(@"任务一");

});

//执行任务二

dispatch_group_async(group, queue, ^{

NSLog(@"任务一");

});

//任务一和任务二执行完毕后在打印结果

dispatch_group_notify(group, queue, ^{

NSLog(@"结果");

});

说明:将异步执行的任务一和任务二放到队列组中,两个完成执行后再执行打印结果的代码。


资源链接链接:http://www.jianshu.com/p/8a7ebecc06f8

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354