面经-OS

239 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

进程和线程

进程是程序的一次执行,进程是资源分配的最小单位,线程是cpu运行的最小单位,一个进程里可以包含多个线程

进程线程的切换

进程切换需要切换页目录和新的地址空间,切换内核栈和上下文 线程切换只切换栈和上下文

进程

一个进程能有几个堆,几个栈

堆有一个,栈各线程独占

进程的通信方式

父子进程 管道 无亲缘进程 有名管道 消息队列 消息队列中的消息有类型,读的时候可以按某种类型筛选 共享存储 效率高,少量数据拷贝,共享内存在内存里开辟一个空间,每个内存映射进来; mmap是在进程的内存里 信号量 进程同步互斥,用于有序的访问某个资源 信号 通知某个进程事件发生 socket

如何创建进程

fork()创建一个就绪态的进程,然后会进入系统调用sysfork,在内核态调度,之后sysclone,sysclone调用copyprocess复制一份父进程除了stack指针以外的全部信息,子进程记录父进程的标志,设置子进程的堆栈,之后调用schedfork把子进程状态设置为running然后调用copythread来复制线程,复制寄存器的值以及父进程的环境,然后子进程从父进程中分离出去,子进程有了pid号,之后就是wakeupnewtask子进程开始执行。 但实际上,由于copy on write原理,fork之后,内核会先把父进程中所有内存权限设置为readonly,子进程的地址空间指向父进程,父子进程如果都只读的话那就没事,如果某个进程要写内存,但这时候内存页式readonly,缺页中断,这时候内核会把页复制一份,父子各拿一份

fork{
	do_fork(){
		copy_process(){
			dup_task_struct()复制过来要赋值,除了stack不同,其他都和父进程一样
			sched_fork()初始化数据结构,状态设置为taskrunning
			copy_thread()
		}
		wake_up_new_process()
	}
}

进程调度策略

FCFS SJF 时间片轮转 优先级调度 高响应比优先 多级队列

为什么操作系统不是一个进程

进程内资源共享,多个线程共用一套资源,如果只有一个进程,线程之间就有互相修改数据的可能

线程

线程池

一个程序的运行就可以被看做一个进程,线程是程序运行中实际的任务执行者,线程池中有核心线程和非核心线程,如果有任务,先给核心线程,核心线程满了就放给任务队列,队列也满了,如果线程数没超,就给非核心线程,如果超了就拒绝,拒绝策略为,线程池满了/啥也不说/插队进队列头/execute

线程的同步

线程私有区和共享区

线程间栈共享,堆不共享

线程越多越好吗

当线程数较少时,cpu管理各线程不存在线程调度的上下文切换,当线程数增加时,线程在cpu间切换,线程切换需要切换栈和上下文,当程序运行的效率低于栈切换所消耗的资源时,效率就会降低,当线程数越来越大时,资源主要就浪费在了线程切换的消耗上

死锁

线程或进程使用某一资源时,需要对该资源独占,

死锁的四个条件

互斥:资源被独立占用 请求保持:阻塞但不释放资源 不剥夺:只能等自己释放 环路:必然存在一个环形请求资源链

预防死锁

一次性分配完资源 有一个资源没准备好,那别的资源我也不给你 我没得到所有的资源,就把已经得到的这部分资源释放了

如何排查并解决死锁

pstack & gdb

单核情况下考虑锁机制吗

考虑,单核心但进程数可以很多,只要有多进程就会死锁

多线程有哪些锁

读写锁的特点

乐观锁 & 悲观锁

自旋锁

页式 & 段式

用户态 & 内核态

逻辑地址怎么转换成物理地址

逻辑地址/页大小,得到页号,逻辑地址%页大小,得到页内偏移,根据页号找对应的块号