runloop
runloop 是用来管理在线程中的异步消息的,一个runloop检测来自线程的不同的数据源,事件到来就启动线程,分发事件给runloop,runloop再把事件分发给handler,没有事件,runloop就停止了。
使用runloop并不是必须的,但是使用它会使得你的程序体验更好,runloop可以用最少的资源创建一个长期运行的线程,从而可以处理一些逻辑。
处理runloop,必须启动线程,获取runloop的引用,注册handler,启动runloop,系统默认会设置好主线程的runloop,但是子线程的runloop就需要自己自己配置了。
runloops 的详细信息
数据同步 synchroniztion tools
使用多线程肯定会导致资源竞争的问题,你可以让一个线程只管理同一块数据。但是当必须共享资源的时候,你就必须同步资源,使用原子操作,线程锁或者其他的技术。
线程锁可以保证同一时间只有一个线程在操作同一份数据,直到这个线程昨晚操作。cocoa也提供了很多线程锁 线程锁
系统提供了 条件锁 ,条件会限制线程运行直到达到这个条件为止。
原子操作性也是一个解决方案。同步数据方案
线程间的数据交互
线程间的数据交互也是非常重要的,因为有数据交互才会对线程的结果进行处理,多线程才有意义。
方法 | 描述 |
---|---|
直接执行 | cocoa 可以直接在另外一个线程中执行方法,一个线程给另外一个线程发的消息可以直接进入另外的线程 |
全局变量 | 全局变量或者共享内存,会导致数据同步问题,所以需要谨慎使用。 |
条件执行 | 根据条件执行线程使用条件 |
runloop数据源 | 可以接受程序指定的数据源。可以达到线程间交互的功能。runloop |
ports和sockets | port 可以跟runloop配合使用,并且比较可靠。 |
message queues | FIFO 且比较复杂 |
cocoa distributed objects | 比较复杂,且更适用于进程交互。 |
设计要点
尽量避免多线程或者可以转而使用一些封装的api
因为多线程易于产生错误,所以尽量避免使用线程,而可以使用一些异步的api,和GCD,他们已经帮忙处理好了一些线程相关的工作。而且肯定会比你处理得好。异步编程指南
物尽其用,或者叫(线程)尽其用
线程还是会占用大量的资源,所以能今早结束就把他结束吧
避免线程数据竞争
最好的就是给每个线程一份独立的数据或者copy, Changing your code to a transaction-based model to compensate could subsequently negate the performance advantage of having multiple threads.
界面相关的进程
界面相关的进程建议直接在主线程做,可以避免用户事件和绘图问题。
有些多线程方法处理界面的提升也比较值得注意,比如使用子线程进行图片的绘制。thread safety summary
cocoa 绘图参考:Cocoa Drawing Guide.
注意线程退出时的线程表现
程序会等待所有的非独立线程结束的时候结束,主线程是非独立(non-detached)当然你也可自己创建非独立的线程。因为有的时候用户会自己结束程序,这时候独立的(detached)线程会直接结束,如果你正好在做一些缓存或者网络上传的动作,这个时候就会发生错误了。
如果你想创建非独立的线程的话,你可能必须要用posix api。创建独立线程
还有一个方法就是在applicationShouldTerminate: 代理中进行拖延程序结束时间。然后处理完之后再调用replyToApplicationShouldTerminate:方法
处理好线程里的崩溃问题
彻底的关掉你的线程
尽量让线程自然关闭,不要使用一些强制关闭代码,因为有可能这个线程正在申请内存,打开文件,如果你直接关闭了,那么就会导致这一部分资源泄露。关闭线程
库开发者需要注意的多线程安全
库开发者更需要注意线程安全,因为你不能从程序的全局控制线程,在开发的时候你必须假设程序已经运行在了多线程的情况下,所以你可能要对关键代码加锁。此外应该注意效率问题。