线程(一)About Theaded Programming


文本取材自苹果的官方文档。


下面是连接:Threading Programming Guide | go to ~


(一)关于线程程序设计

    多年之前的多个年头,计算机的运行依靠唯一一个叫做微处理器的核心,速度是各种慢,后来出现了多核芯片这个大明星,让计算机能够实现异步同事处理多条任务。现在的各种系统可以利用这个明星核的特点去执行系统相关任务,应用程序也可以通过线程来利用星核的特殊能力。

1.  什么是线程?(What Are Threads

    * 线程是运行在应用程序中的 相对轻量级的 实现多路径的方法。

    * 从系统层面说,程序并排运行着,系统根据程序进程需要分配给每一个程序执行时间,而在程序之中,存在一个或多个线程,程序的任务靠这些线程同步或几乎同步执行。系统会控制管理这些线程,规划它们去占用芯核并根据优先级编排插入需要处理的线程。

    *在一个非并发程序中,只要一个线程,开始并结束与应用程序的 main 例程函数,并顺序执行其中的方法来完成程序的行为。相对于的支持并发需要添加创建新的可执行路径,每一条新路径都有自己的启动例程,独立于应用程序main例程的,一个应用程序使用到多线程有两个重要的潜在好处

    a. 多线程可以优化应用程序的感知响应能力(体验上就是更加流畅)

    c. 多线程可以优化应用程序在多核系统中的实时性能(充分发挥多芯核处理器的特性)

    * 如果应用程序只有一个线程,那么它需要完成所有的事情(相应事件,更新界面,计算处理),问题是一个线程同一时刻只能处理一件事情,如果一个耗时任务开始执行,那么别的任务只好排队等待。(如果实在进行计算处理任务,就不会对事件进行相应,就不会对界面进行更新,造成卡顿现象),多线程可以解决这个问题。

    * 多线程不是解决程序所有问题的万能药,应用多线程也会有一些问题:a.必然会增加代码的复杂度 b.一个应用程序中的线程能够共享它的相同的内存空间,取到同样的数据结构,线程间可能同时更改某一块数据,造成错误。所以需要细心优化处理好线程安全问题。


2.  线程相关术语(Threading Terminology

    thead   (线程)指单独的一条代码执行任务

    process (进行)指一个运行的执行程序,可能包含多条线程(至少包含一条线程)

    task    (任务)一个抽象的概念,指需要执行的任务。


3.  可使用的为线程服务的手段(Alternatives to Threads

    * 给代码创建添加新线程,就是添加了不确定性,因为线程是支持程序并发的相对底层和复杂的方法。选择使用不当,可能会造成同步问题或时机把控问题,一些微妙的小变化就可能导致程序崩溃,也会弄坏了用户数据。

    * 需要考虑好是否的确需要多线程或者并发处理,线程是解决怎样在同一个进程中执行多任务处理的方法。线程启动会存在内存消耗和CPU时间占用,所以也是有代价的,是否使用需要综合考虑。

    * 线程技术列表

    (1). Operation Objects          |对新线程执行任务的一个对象封装,隐藏了线程管理的任务分配和,保留了处理任务的接口,可以与运行队列对象组合使用。


    (2). Grand Central Dispatch     |它更强调的是的是任务处理,而不是线程的管理(它自己做线程管理),使用GCD,只需要定义好任务然后添加到工作队列中,它会自动安排任务执行所合适的线程,工作队列对可用芯核的利用比自己管理使用线程更加有效。


    (3). idle-time notifications    | 很短、低优先级的任务,闲置时间通知可以让程序在闲适时间处理一些小任务,Cocoa 提供的有NSNotificationQueue对象,利用NSPostWhenIdle选项给默认的NSNotificationQueue发一个通知,队列会延迟直到run loop(运行池子)闲置的时候去传递讯息。


    (4). Asynchronous function      | 系统接口包含许多异步函数提供自动处理并发问题,


    (5). Timers                     | Timer Sources


    (6). Separate processes         | 比线程重的,但如果处理任务与当前应用程序无关来使用它很有用,或者必须执行比较底层特权的东西,比如需要使用64位的处理大数据然后用32位的应用程序给用户展示数据。



4.  线程支持(Threading Support

    * 介绍一些核心的线程技术,

    1)线程使用包(Threading Packages

        //首先更底层实现线程机制的那个东西叫做 Mach thread。但是一般程序开发人员绝少用到Mach level的技术来处理线程,通常使用的都是更加便捷的 POSIX API 或者一些基于它的衍生技术。

        //线程技术(Thread technologies

        <1>.Cocoa thread    |使用 NSThread 类, NSObject提供有可以使用到NSThread的接口(PSEL

        <2>.POSIX thread    |基于C的接口,如果不是Cocoas 应用程序,它是创建线程最好的选择,它提供了一套相对简单当时又比较丰富的处理线程的方法。

        <3>.Multiprocessing Services|苹果建议,忘掉它吧,使用NSTread is good

        //对于所有线程来说都有三个状态:(运行|running,准备|ready,阻塞|blocked),如果不是退出了他们将始终都是在这条三个状态的路上。


    2)运行池子(Run Loops

        //在苹果程序中,它和线程关系密切,可以说是伴生关系,每一个线程都有一个它,了解更多信息可以参看更多RunLoops相关文档。:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1


    3)同步工具(Synchronization Tools

        使用多线程最大的一个麻烦是资源争夺的问题,多个线程同时去更改一块数据源,问题就出现了。解决这个问题就必须对数据源接口进行同步处理,可以使用:locksconditionsatomic operations,等其他技术手段。

        a.锁,强制保护代码在同一时刻只能被一个线程使用,常用的类型是互斥锁(mutual exclusion lock,就是mutex

        b.条件,conditions更显是一个看门人,保证程序中的任务执行序列,在描述的条件成真之前都阻塞线程。POSIX he Foundation框架都直接支持conditions。(如果使用operation Objects ,运行对象的任务队列中设置的依赖关系就很像conditions的行为)。

        c.源自操作,它提供了一个轻量级的方法来实现数据接口的同步,Atomic operations是使用特殊的硬件指令去保证那个被修饰的变量,先于其他的线程。


    4)线程间通讯(Inter-thread Communication

        好的设计尽量减少通讯发生,有的时候线程间通讯确实必须的。其实,线程会共享一块共同的进程区间,通过它就可以有多重线程间通讯的方法了。不同方法各有特色。

        通讯机制(Communication mechanisms):

        <1>.Direct messaging    | 使用PSEL方法,(Cocoa Perform Selector Sources.

        <2>.Global variales,shared memory,and objects | 共享变量需要小心使用锁或者其它同步机制保护好。

        <3>.Conditions          | 同步工具的一种,

        <4>.Run Loop sources    |

        <5>.Ports and sockets   | 基于端口的线程通讯复杂精致可靠。并能实现与外部实体的通讯(如其他进程和服务)

        <6>.Message Queues      |

        <7>.Cocoa distributed Objects|



#if 0


5.  设计小提议(Design Tips

    1)避免显明的创建线程

        显明创建线程的代码冗长而容易出错,苹果系统提供了处理并发的一些API,可以替代自己创建线程,如可以使用异步APIsGCDoperation objects。这些技术在后台处理线程关系,并能够保证正确处理,除此之外,相信GCD operation objects 方法比你自己写的线程代码要有效很多。


    2)维持自建线程的合理运营(Keep Your Threads Reasonably Busy

        理由有,线程其实很消耗宝贵的系统资源,(物理内存,CPU,占用总线),所以就需要充分确保任务合理给到线程,如果一个线程闲置,最好把它终结掉。


    3)避免共享数据(Avoid Shared Data Structures)

        最简单的避免线程间关联数据冲突的方法就是,copy需要的数据,保持线程间独立,减少线程间通讯。


    4)线程与用户界面关系(Threads and Your User Interface)

        建议所有的UI操作都搁置到主线程中,当时可以把一些非UI的操作放置到自己的线程中,以达到优化程序运行流畅的效果,如进行一张图片的创建处理和相关计算可以放在异步线程中,界面渲染的工作再交给主线程来完成。


    5)注意程序退出时候的线程处理(Be Aware of Thread Behaviors at Quit Time)

        进程退出的标志就是所有的non-detachedalso known as joinable)线程都已经退出。而我们一个应用程序默认只有主线程是non-detached,其他新建的线程一般都不是,这样子就算退出程序一般情况没问题,如果有一个线程正在对数据处理并要度写道磁盘,如果突然中断进程,必然导致数据损失。这时候就要靠non-detached类型的线程来解决问题了。然而大多数比较high-level的线程技术都没有创建joinale的接口,可以使用POSIX PAI来创建,并且,必须添加代码到应用程序的主线程。

        如果是Cocoa 应用程序,也可以利用 applicationShouldTerminate: 代理方法去延迟程序的终结,当延迟结束进程的时候,可以在对应的线程中添加 replyToApplicationShouldTerminate:方法,在线程任务结束时候告知程序可以结束进程了。


    6)异常处理(Handle Exceptions

        每一个线程都有自己的调用堆栈,异常处理机制依赖于当前线程堆栈中必要的清理工作。线程的异常处理也只在自己的堆栈中,所以需要每一个线程单独处理好自己的异常情况。在Cocoa 中有一个NSException对象,可以实现线程间传递。


    7)线程结束清理(Terminate Your Threads Cleanly

        一个线程一般自然的状况是,从入口进入,任务执行完毕,就会自动结束退出。当然也可以利用函数李可结束进程(这种方法除非迫不得已不要使用)。在线程退出之前,处理线程中开辟的内存,打开的文件,或者其他的一些引用资源,处理不好就会导致内存泄露以及一些其他问题。


    8)库资源的线程安全(Thread Safety in Libraries

        如果是一个框架或库开发,需要对核心代码做好同步处理(如用锁机制),确定确保黄芪程序是可以多线程的或者可以任何时候转化整支持多线程的。开发一个库,锁机制最好趁早添加上,不要只在程序编程多线程的时候添加。



结语:

*文档对线程做了一个科普,毕竟是针对苹果开发者,所以里头介绍的到的相关技术点都是基于apple技术的。

*没有说到具体一个线程怎么创建的代码或者API,告诉的是用的是什么方法,什么技术点,技术点的介绍。所以如果要知道譬如NSThread到底怎么用,这需要深入到NSThread的API文档说明和代码示例中区研究。

*就像一副画,大家看了一眼之后都有一个大体的映像,也许可以描述出画的要素点(概念),但是却几乎不可能站我图画元素的详细绘制方法的,如果想要自我构造,还得深入学习譬如一个色彩的配置方法等,这篇文档给人感觉就是一副画图展示而已,并且顺带了每一个元素点都给总结成目录了,知道按需求深入研究。

*整个下来感觉apple文档有点儿像一篇应用程序线程设计口诀概要,但是没有总结出顺口的诀来,总而言之,且行且努力。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值