runloop:
保证程序不退出,负责监听事件,监听iOS的所有事件,触摸,时钟,网络事件。
如果没有事件会让程序进入休眠状态。
//如果时钟触发方法,执行非常耗的操作!! UI界面会卡。
Runloop :内部维护事件循环来对事件/消息进行管理的一个对象。
1.没有消息需要处理的时候,休眠避免占用资源。不是简单的while for循环。
2.有消息处理的时候,立刻被唤醒。
没有消息需要处理时候,休眠以避免资源占用。
API 用户态—内核态 (操作系统的指令)
有消息处理的时候。
内核态度——用户态。状态的切换。
Int. main(){
执行体 runloop接受消息,处理,等待。
}
NSRunLoop Foundation
CFRunLoop CoreFoundation .——开源
事件循环,
数据结构,
CFRunloop ——pthread(线程一一对应),
currentMode(cfrunloopmode),
modes <集合 CFRunloopMode>
.commonModes<集合 字符串>——不同模式的名称。
comonModeltems.<集合 多个oberser timer source>
CFRunloopMode.
name. — nsdefaultRunloopMode 字符串类型。别名字符串。
sources0.——集合 无序 ——需要手动唤醒线程。 内核态—用户态。
sources1——集合无序—具备唤醒线程的能力。
observes—数组有序
timers—数组有序
Source
Timer:基于事件的定时器。NSTimer是免费桥转换。
Observer.:观测时间点。相关时间点的观察。
1.runloopEntry:入口,启动的时候,回掉通知。
2.beforetimer 通知观察者,timer事件进行处理。
3.before Source,将要处理一些source事件。
4.beforewaiting 进入休眠状态。
5.afterwaiting 内核态,用户态切换。
6.exit ,退出的通知。
一个runloop /对应一个线程 /对应多个model/source/timer/observer/
model 屏蔽的效果。
timer 同时添加到两个model中。
CommonMode:
NSRunLoopCommonModes.不是实际存在的一种Mode.
是同步source.timer,observer多个Mode的结局方案。
事件循环的实现机制:
CFRunLoopRun()
有事情做事情,没事休息。系统怎么实现的。
1.即将进入RunLoop.
2.将要处理Timer.
3.将要处理source0的事件
4.处理source0事件。
5.如果有source1要处理————处理唤醒消息,然后回到2 timer
6.线程将要休眠。
7.休眠等待唤醒。————source1 timer 外部手动唤醒。
RunLoop核心
main()
mach_msg()—系统调用——核心态—mach_msg—唤醒线程。
数据结构,
事件循环机制,
runloop与NSTime:
滑动tableview的时候 我们的定时器还会生效吗?
runloopdefaultMode,——uitrackingRunloop
cfrunloopaddTimer (runloop.timer,commonMode);打上一个标记,同步到多个model当中。
Runloop与多线程
线程和runloop 一一对应的,数据结构
默认情况下是没有创建的。
1.当前线程开启一个Runloop。
2.向该Runloop中添加一个Port/Source 等维持Runloop的事件。
3.启动该Runloop。
常驻线程。
MCObject. runalways .
source1 :基于port
https://blog.csdn.net/jeffasd/article/details/52027733
https://www.jianshu.com/u/1f93e3b1f3da
https://www.jianshu.com/p/b4bea1549a66
②CFRunLoopSource
source是RunLoop的数据源(输入源)的抽象类(protocol)
RunLoop定义了两个version的Source:
i.source0:处理App内部事件,App自己负责管理(出发),如UIEvent、CFSocket
ii.source1:由RunLoop和内核管理,Mach Port(进程间通讯端口)驱动,如CFMachPort、CFMessagePort
Source0只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal(rlms)方法将这个Source标记为待处理,然后手动调用CFRunLoopWakeUp(rl)方法来唤醒RunLoop,让其处理这个事件。
//设置全局的字典,key为主线程,value为主线程关联的RunLoop对象
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
都是调用_CFRunLoopGet0函数,通过源码可知runloop的存储方式是键值对,key是当前线程,value是runloop,线程和runloop是一对一的关系,当字典为空的时候会默认创建主线程的runloop,而子线程在获取的时候才会创建。
https://www.jianshu.com/p/cfe5132e975f
1.runloop 里面包含很多的model。
2.runloop 不能创建,get0函数来获取自动创建,跟线程一一对应,线程当key object 是runloop 存到字典里面。
3. CFRunLoopRun
do{
0.查找currentMode是否为空。如果为空就return.
1.通知监听器Runloop进入循环。
do{
2.通知监听器即将处理Timer事件。
3.通知监听器处理source0
4.执行source0事件
5.如果有source1 (基于端口)事件 立即执行,条转到第九步。
6.通知监听器Runloop即将进入休眠状态。
7.将线程休眠,直到以下事件发生才会被唤醒。
mach_msg 等待接受 mach_port 的消息。线程将进入休眠, 直到被下面某一个事件唤醒。
【 1.有source1事件到达,
2.定时器出发时间到达,
3.runloop 对象的超时时间过期
4.被外部显示唤醒。
】
8通知监听器runloop 对象被即将唤醒。
9.处理添加进来的事件。
1.用户定义的定时器时间到达,执行定时器时间并重启循环,跳转到第二部。
2.如果有source1事件,传递这个事件。
3.如果runloop 被显示唤醒,并且没有超时则重启runloop 跳转到第二部。
}while()
10.通知监听器Runloop退出循环。
}while()
3.iOS内核
https://www.jianshu.com/p/a1a2921f2399
1.内核是操作系统中最为关键的部分,内核是负责接触底层的。用c语言写的,有的是汇编语言。iOS的核心就是XNU内核。
XNU:
Mach+FreeBSD+IOKit 的驱动程序
XN内核是用于OSX iOS操作系统的Darwin操作系统的一部分。XNU是is not unix的缩写。
XNU 是将卡内基梅隆大学研发的 Mach 内核与 FreeBSD 和 C ++ API 的组件相结合的混合内核,用于编写名为 IOKit 的驱动程序
1.由于Unix内核是纯文字界面(不像Windows内核已经整合了许多图形界面的东西)
2.https://kb.cnblogs.com/page/114879/
https://bbs.feng.com/read-htm-tid-4998822.html
内核故事
Mac OS X的底层也沿用NeXTSTEP的架构,但又有所不同。其中Mach改用一个名为osfmk的变体,BSD在2000年之后逐步转向FreeBSD,而最惨的当属Driver Kit,不但改了个名叫I/O Kit,连实现它的编程语言都改成了C++
https://baike.baidu.com/item/MACH/216388
https://kb.cnblogs.com/page/114879/#s11
单核 :就是包含所有的服务,上至内存管理,下至设备驱动,应有尽有。
微内核:只包括最核心的功能(硬件访问、调度、虚拟内存管理)。既然微内核存在,那么必有可取之处。相比巨内核。
混合内核:混合内核试图包含前两种内核好处。混合内核的核心部分支持底层服务,就像微内核一样,而其他服务虽然不在该核心的“微内核”中,但是也包含在该核心中,其他服务可以调用该核心的“微内核”。混合内核相比于其他内核架构,牺牲了微内核的健壮性换来巨内核一样的运行效率。
https://www.jianshu.com/p/a1a2921f2399
https://www.jianshu.com/p/362bbf4cb114
https://www.jianshu.com/p/a1a2921f2399
https://www.cnblogs.com/bakari/p/5520860.html
然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。
当我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。
对不同的操作赋予不同的执行等级,就是所谓特权的概念。简单说就是有多大能力做多大的事,与系统相关的一些特别关键的操作必须由最高特权的程序来完成。Intel的X86架构的CPU提供了0到3四个特权级,数字越小,特权越高,Linux操作系统中主要采用了0和3两个特权级,分别对应的就是内核态和用户态。运行于用户态的进程可以执行的操作和访问的资源都会受到极大的限制,而运行在内核态的进程则可以执行任何操作并且在资源的使用上没有限制。很多程序开始时运行于用户态,但在执行的过程中,一些操作需要在内核权限下才能执行,这就涉及到一个从用户态切换到内核态的过程。比如C函数库中的内存分配函数malloc(),它具体是使用sbrk()系统调用来分配内存,当malloc调用sbrk()的时候就涉及一次从用户态到内核态的切换,类似的函数还有printf(),调用的是wirte()系统调用来输出字符串,等等。
网友评论