linux进程、线程及调度算法(二)
执行一个 copy,但是只要任何修改,都造成分裂如,修改了chroot,写memory,mmap,sigaction 等。 p1 是一个 task_struct, p2 也是一个 task_struct. linux内核的调度器只认得task_struck (不管你是进程还是线程), 对其进行调度。 p2 的task_struck 被创建出来后,也有一份自己的资源。但是这些资源会短暂的与p1 相同。 进程是区分资源的单位,你的资源是我的资源,那从概念上将就不叫进程。 其他资源都好分配,唯一比较难的是内存资源的重新分配。 非常简单的程序,但是可以充分说明 COW。 结果:10 -> 20 -> 10 COW 是严重依赖于CPU中的MMU。CPU如果没有 MMU,fork 是不能工作的。 在没有mmu的CPU中,不可能执行COW 的,所以只有vfork vfork与fork相比的不同 P2没有自己的 task_struct, 也就是说P1 的内存资源 就是 P2的内存资源。 结果 10,20,20 vfork: vfork 执行上述流程,P2也只是指向了P1的mm,那么将这个vfork 放大,其余的也全部clone,共同指向P1,那么就是线程的属性了。 phtread_create -> Clone() P1 P2 在内核中都是 task_struct. 都可以被调度。共享资源可调度,即线程。 这就是线程为什么也叫做轻量级进程 不需要太纠结线程和进程的区别。 4651 : TGID 4652, 4653 tid 内核中 task_struct 真正的pid linux 总是白发人 送 黑发人。如果父进程在子进程推出前挂掉了。那么子进程应该怎么办? p3 -> init, p5 -> subreaper 每一个孤儿都会找最近的火葬场 可以设置进程的属性,将其变为subreaper,会像1号进程那样收养孤儿进程。 linux的进程睡眠依靠等待队列,这样的机制类似与涉及模式中的订阅与发布。 睡眠,分两种 每一个进程都是创建出来的,那么第一个进程是谁创建的呢? init 进程是被linux的 0 进程 创建出来的。开机创建。 父进程就是 0 号进程,但在pstree,是看不到0进程的。因为0进程创建子进程后,就退化成了idle进程。 idle进程是 linux内核里,特殊调度类。 所有进程都睡眠停止 ,则调度idle进程,进入到 wait for interrupte 等中断。此时 cpu及其省电,除非来一个中断,才能再次被唤醒。 唤醒后的任何进程,从调度的角度上说,都比idle进程地位高。idle是调度级别最最低的进程。 0 进程 一跑,则进入等中断。一旦其他进程被唤醒,就轮不到 0进程了。 所有进程都睡了,0就上来,则cpu需要进入省电模式
linux进程、线程及调度算法(三)
调度策略值得是大家都在ready时,并且CPU已经被调度时,决定谁来运行,谁来被调度。 两者之间有一定矛盾。 响应的优化,意味着高优先级会抢占优先级,会花时间在上下文切换,会影响吞吐。 上下文切换的时间是很短的,几微妙就能搞定。上下文切换本身对吞吐并多大影响, 重要的是,切换后引起的cpu 的 cache miss. 每次切换APP, 数据都要重新load一次。 Linux 会尽可能的在响应与吞吐之间寻找平衡。比如在编译linux的时候,会让你选择 kernal features -> Preemption model. 抢占模型会影响linux的调度算法。 所以 ARM 的架构都是big+LITTLE, 一个很猛CPU+ 多个 性能较差的 CPU, 那么可以把I/O型任务的调度 放在 LITTLE CPU上。需要计算的放在big上。 早期2.6 内核将优先级划分了 0-139 bit的优先级。数值越低,优先级越高。0-99优先级 都是 RT(即时响应)的 ,100-139都是非RT的,即normal。 调度的时候 看哪个bitmap 中的 优先级上有任务ready。可能多个任务哦。 在普通优先级线程调度中,高优先级并不代表对低优先级的绝对优势。会在不同优先级进行轮转。 100 就是比101高,101也会比102高,但100 不会堵着101。 众屌丝进程在轮转时,优先级高的: 初始设置nice值为0,linux 会探测 你是喜欢睡眠,还是干活。越喜欢睡,linux 越奖励你,优先级上升(nice值减少)。越喜欢干活,优先级下降(nice值增加)。所以一个进程在linux中,干着干着 优先级越低,睡着睡着 优先级越高。 后期linux补丁中 红黑树,数据结构, 左边节点小于右边节点 同时兼顾了 CPU/IO 和 nice。 数值代表着 进程运行到目前为止的virtual runtime 时间。 (pyhsical runtime) / weight * 1024(系数)。 优先调度 节点值(vruntime)最小的线程。权重weight 其实有nice 来控制。 一个线程一旦被调度到,则物理运行时间增加,vruntime增加,往左边走。 weight的增加,也导致vruntime减小,往右边走。 总之 CFS让线程 从左滚到右,从右滚到左。即照顾了I/O(喜欢睡,分子小) 也 照顾了 nice值低(分母高).所以 由喜欢睡,nice值又低的线程,最容易被调度到。 自动调整,无需向nice一样做出奖励惩罚动作,个人理解权重其实相当于nice 但是 此时 来一个 0-99的线程,进行RT调度,都可以瞬间秒杀你!因为人家不是普通的,是RT的! 一个多线程的进程中,每个线程的调度的策略 如 fifo rr normal, 都可以不同。每一个的优先级都可以不一样。 实验举例, 创建2个线程,同时开2个: 运行2次,创建两个进程 sudo renice -n -5(nice -5级别) -g(global), 会明显看到 一个进程的CPU占用率是另一个的 3倍。 为什么cpu都已经达到200%,为什么系统不觉得卡呢?因为,我们的线程在未设置优先级时,是normal调度模式,且是 CPU消耗型 调度级别其实不高。 利用chrt工具,可以将进程 调整为 50 从normal的调度策略 升为RT (fifo)级别的调度策略,会出现: chrt , nice renice 的调度策略 都是以线程为单位的,以上 设置的将进程下的所有线程进行设置nice值 线程是调度单位,进程不是,进程是资源封装单位! 两个同样死循环的normal优先级线程,其中一个nice值降低,该线程的CPU 利用率就会比另一个CPU的利用率高。