linux调度
本质:虚拟处理器,虚拟内存
分类:抢占,非抢占。IO/处理器型
调度
优先级
nice 与其他系统不同是时间片比例,-20~19(越小越高)
实时优先级 0-99 越大越高 高于普通的nice
调度器
1.CFS
时间记账:task_struct的se vruntime(这个时间是经过了所有可运行进程总数的标准化,理想下相同优先级有相同vruntime)
选择最小vruntime 红黑树 可运行队列,最左侧节点缓存
2.实时调度FIFO,RR,IDLE
FIFO:一直运行直到阻塞/更高优先级的抢占
RR:有时间片,耗尽后,同优先级轮流
IDLE 比nice19优先级还低
cpu高速缓冲器(1行 32-128字节)
getruasge
getrlimit
内核系统调用 帮助进程通信,访问硬件,申请资源
软中断 0x80=》system_call eaax寄存器中断号 参数:寄存器中,若多于6个,用单独寄存器存放指向所有参数在用户空间地址的指针 返回值:eax寄存器
进程状态
- runing(sleep也是run)
- 可中断睡眠(系统调用等软中断)
- 不可中断(硬中断)忽略信号
等待队列简单链表wait_queue_head_t=》队列相关事件发生时wake_up=>try_to_wake_up 加入红黑树 设置need_resched
进程上下文切换:switch_mm 把虚拟内存从上一个进程映射切换到新进程中。switch_to负责从上一个进程的处理器状态切换到新进程的处理状态,保存/恢复栈信息/寄存器信息
用户抢占(用户间切换是安全的):从系统调用过或中断返回用户空间,need_resched设置掉schedule()
内核抢占(抢占内核进程),中断返回内核(内核进程thread_info的preempt_count=0&&need_resched),内核进程阻塞,显示调用会调用 - traced stopped
进程内存管理
sched.h task_struct (slab分配该结构) 内核栈底,所有task_struct已双向链表组织在一起,task list
current宏
虚拟内存
栈 参数,env 栈指针 sp寄存器
堆
未初始化
初始化
文本
页表(空页未使用虚拟空间无页表)
RAM(只有程序的部分页 ) swap
进程操作
- fork
复制父进程页表 创建pid 父写也会复制,立即exec省去复制过程(都是clone=>do_fork)
文件描述符副本相互影响
代码段只读,共享,页表项指向父进程相同RAM页
其他段写时复制
fork后哪个先更好?在二者不变时是没有任何复制的(指的是RAM页内容,前几级的页表还是要复制的),所以,子先直接exec(父未执行) 避免了页的拷贝,要优化这个可以在进程刚起来就起几个Pid用来做后面的exec
父先cpu中活跃提高性能,但是可能会引起写时复制 - vfork 不拷贝页表(不推荐使用)
- 内核线程 mm为Null
- exit 删除定时器,ipc信号,文件,向父进程发信号,剩余内核栈,thread_info,task_struct
调用atexit/on_exit注册函数
刷stddio缓冲区
_exit 关闭fd。文件锁/sem_close/mq_close,取消mmap,mlock等
print fork exit
print是stdio函数有缓冲区,fork时在用户空间内存上复制 exit刷新。会打印两份print内容(若write只有一份)
setbuf.print前fflush。一个进程用exit其他_exit - wait 挂起直到子进程退出
waitpid 可指定pid 非阻塞
wait3 wait4 统计rusage
zomble
SIGHUP 子进程终止发给父进程=》循环waitpid - execve 重新创建栈 数据段,
线程
线程 pthread linuxthread(千线程)/nptl(10万) 比进程快10倍
独有:tid,信号mask,栈,浮点型环境,优先级,cpu亲和力等
线程同步:互斥量/条件变量
1.静态phreaad_mutex_initializer lock try_lock不阻塞
性能:文件锁/信号量 锁定和解锁总需要发起系统调用,互斥量在内存中执行对所有线程可见,只有发生锁征用时 futext()系统调用
避免死锁:按顺序 lock->try_lock失败释放所有
动态 pthread_mutext_init()
2.条件变量
pthread_cond_initilizer signal breadcast wait
这个变量也要加互斥量 lock wait(unlock xxx lock) unlock
线程安全:互斥量
thread_once
线程特有数据 pthread_key_create pthread_setspecific 一个全局数组 为每个线程设置与key对应元素
线程局部存储 __thread每个线程有一个拷贝
其他操作
cancel 延时取消,到取消点(可作为取消点的函数比如print,sleep等) 取消点前可以调用清理函数。异步取消任何时候取消不能完好清理
信号 动作/处置是进程层面的,真对线程:pthread_kill等
多线程收到一个信号,已创建handler 选一条线程接收处理
exec 任意线程调用 程序被替换,其他线程消失,线程ID不定
fork 子进程复制这一线程,包括互斥量等
exit 任何线程调用,全消失
线程与调度实体,采取1:1实现 每个线程为一个KSE,都要切到内核 (M:1调度等由用户线程处理)
会话
会话首进程 pid ppid pgid组 sid会话
进程组 首pid
非首进程 setsid会创建一个新会话
会话的孤儿进程组,停止但未终止,不会被回收(发HUP->CONT解决)
daemon
cron sshd httpd inetdd
daemon过程:
fork
子进程setsid
若已打开过终端再fork子进程不会成为会话组长,不会重新打开终端
清除umask,修改工作目录,关闭父进程fd
信号处理
syslog
问题
1.进程和线程的区别(进程独立数据地址空间),父子进程共享哪些内容,线程独占哪些内容;进程创建和线程创建初始化的资源;
fork 区别pid,ppid,某些统计量,某些资源比如挂起的信号。拷贝或共享打开的文件,文件系统信息,信号处理函数,进程地址空间,命名空间。
具体:创建内核栈,thread_info,task_struct。初始化。分配pid。共享/拷贝进程地址空间页表等。线程前6个也差不多。共享的更多。
但最终两个进程相同程序文本段,共享文件描述符。各自不同栈,数据段,堆等P505
线程:共享的地址空间,文件资源和处理,文件描述符,nice值等 clone(clone_vm|clone_fs|clonne_files|clone_sighand,0)
独有:tid,信号mask,线程独有数据,栈,浮点型环境,cpu亲和力等 p511
2.进程调度方式,进程什么情况会休眠;
抢占,调度器:CFS/实时FIFO,RR等。
等待队列简单链表wait_queue_head_t=》队列相关事件发生时wake_up=>try_to_wake_up 加入红黑树 设置need_resched
进程上下文切换:switch_mm 把虚拟内存从上一个进程映射切换到新进程中。switch_to负责从上一个进程的处理器状态切换到新进程的处理状态,保存/恢复栈信息/寄存器信息
用户抢占(用户间切换是安全的):从系统吊用过或中断返回用户空间,need_resched设置掉schedule()
内核抢占(抢占内核进程),中断返回内核(内核进程thread_info的preempt_count=0&&need_resched),内核进程阻塞,显示调用会调用
可中断睡眠(某些阻塞的系统调用/软中断,比如等待终端输入,等待空管道/信号量),不可中断(硬中断)忽略信号
3.系统调用如何传递参数和获取返回结果;
软中断 0x80=》system_call eaax寄存器中断号 参数:寄存器中,若多于6个,用单独寄存器存放指向所有参数在用户空间地址的指针 返回值:eax寄存器
4.内存布局,内核地址和进程地址;
5.系统打开最多文件个数,创建最多进程数,会被那些因素制约;
句柄地址(稳定)→记载着→对象在内存中的地址(不稳定)
其中open files表示的是单个进程最多允许打开的文件句柄数(soket连接数也算在内),默认值是1024。对于一般的程序来说,这个值是足够的
限制?打开句柄=》系统打开表=》文件/ram 句柄对应地址的查询太慢?
进程数:虚拟内存大小。内核task_struct 1.7k(32位),thread_info(比较少)。pid int类型的兼容 可改 几万
6.内核空间和用户空间,内存怎么跟着进程切换;
进程上下文:进程的上下文信息包括, 指向可执行文件的指针, 栈, 内存(数据段和堆), 进程状态, 控制信息(信号等), 寄存器组(栈指针, 指令计数器),硬件上下文(注意中断也要保存硬件上下文只是保存的方法不同)等等
进程上下文切换:switch_mm 把虚拟内存从上一个进程映射切换到新进程中(进程的mm_struct的地址映射,加载页表, 刷出地址转换后备缓冲器(部分或者全部), 向内存管理单元(MMU)提供新的信息)。switch_to负责从上一个进程的处理器状态切换到新进程的处理状态,保存/恢复栈信息/寄存器信息
(https://blog.csdn.net/gatieme...)
7.中断和进程上下文的关系
当程序系统调用到内核空间,内核代表进程执行,并处于进程上个下文中,current宏是有效的,除非高优先级抢占否则退出还恢复用户空间继续执行。中断上下文,内核执行中断处理程序。不会有进程去干扰
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。