进程管理
进程,线程是什么
进程
- 进程:运行编写的代码被编译的可执行文件的过程
- 并行并发:并发是单核不同时间段处理任务,并行是多核分别处理不同的任务。
- 进程的状态: 运行状态,就绪状态,阻塞状态,除此之外还有创建状态和结束状态。但因为内存空间的问题,系统会把
阻塞状态的程序写入的硬盘中,这就需要一个新的状态来描述,即描述进程没有占用实际的物理内存空间的情况,称为挂起状态。
挂起状态又分为阻塞挂起状态(存在外存,等待事件发生)和就绪挂起状态(存在外存,进入内存直接运行)。 - 进程控制结构(PCB):是进程存在的唯一标识,包含进程描述信息,进程控制和管理信息,资源分配清单,cpu相关信息。
— 如何组织这些进程:按照队列分,如就绪队列按照链表依此连接pcb中为就绪状态的进程。
— 如何控制进程:创建(申请新的pcb并写好放入就绪队列中),终止(查找pcb,删除并释放资源),阻塞(修改pcb并
放入阻塞队列),唤醒(转换状态并放入就绪队列)。
线程
- 线程:最小能独立运行的单位,是进程中的一条执行流程,线程之间可以共享资源,但一个线程挂了会导致所有线程崩溃。
- 线程实现:同样有TCB,具体实现分为用户线程(内核不参与,有自己的程序函数进行调控),内核线程,轻量级线程(在内核中支持用户线程),
进程,线程比较
进程 | 线程 |
---|---|
资源分配的单位 | cpu调度的单位 |
拥有完整的资源管理平台 | 只独享必不可少的资源 |
能减少并发执行的时间空间开销 |
调度程序
- 调度算法:分为抢占式(有时间中断,会将进程挂起)和非抢占式(运行直到阻塞或者结束)。
– 再往下可分为:单核下的FCFS(先来先服务算法),SJF(最短作业优先调度算法),高相应比优先调度算法(根据公式计算的:
时间片轮转调度算法,HPF(最高优先调度算法),多级反馈队列调度算法(结合前两者,不同队列运行时间不同)。 - 调度原则:考虑cpu利用率,系统吞吐量,周转时间,等待时间,响应时间。
进程之间如何通信
管道
匿名管道只在父子进程之间通信且随着进程销毁而结束,而命名管道可以在不相关的进程间通信。
管道通信不适合进程间频繁通信。
消息队列
消息队列是保存在内核中的消息链表,消息队列不适合较大数据的传输,且在通信过程中,存在用户态和内核态的数据拷贝开销。
共享内存
其机制是不同进程拿一块虚拟地址空间来,映射到相同的物理内存中。
— 为了防止不同进程修改同一个共享内存,引入概念信号量,其实类似于上锁,参量p和v,p是减1,v是加1。
信号
信号是进程之间唯一的异步通信机制,来源于硬件(如cltr+c)和软件(如kill),进程对信号的处理方式是有执行默认操作,捕捉信号和忽略信号。
Socket
为了实现跨网络与不同主机上的进程之间通信,就需要socket通信了,按照创建类型,可以细分为1.实现TCP字节流通信,实现udp数据报通信
,实现本地进程间通信。
多线程发生冲突
互斥与同步
- 互斥:保证一个线程在临界区执行时其他线程应该被阻止进入临界区。临界区是指访问共享资源的代码片段。
- 同步:并发进线程在一些关键点上可能需要互相等待与互通消息。
- 实现与使用:主要方式有两种:— 锁,—信号量。
— 锁:又分为忙等待锁和无忙等待锁,忙等待锁又被称为自旋锁,意思是当获取不到锁时,会一直循环利用CPU周期
直到锁可用,无等待锁指获取不到锁时需要放入等待锁的队列中。
— 信号量,控制进程进入临界区
生产者消费者问题
- 任何时刻,只有一方可以进入缓冲区
经典同步问题
哲学家就餐问题
可行方案一:让偶数编号的哲学家先拿左边后拿右边,奇数编号相反,每个叉子一个信号量。
可行方案二:用数组记录哲学家三种状态,进餐状态,思考状态,饥饿状态;每个哲学家两边没有进餐时才可以进餐。
每个哲学家一个信号量。
读者写者问题
三种方案分别为读者优先(读者优先进入读者队列),写者优先,和公平策略(阻塞读者或写者在flag处)。
怎样避免死锁
死锁怎样产生
必须同时满足下面的条件:
- 互斥条件: 即多个线程不能使用同一个资源。
- 持有并等待条件:即线程A已经占有资源1,但还想申请资源2。
- 不可剥脱条件:自己在使用完之前不能被其他线程获取资源。
- 环路等待条件:两个线程获取资源的顺序构成了环形链。
如何避免
破坏其中之一的条件即可,通常破坏环路等待条件,使用资源有序分配法,即有序获取资源。
悲观锁和乐观锁
互斥锁和自旋锁
- 互斥锁加锁失败时,系统会从用户态转换为内核态,即释放cpu,给到其他线程。但这样会有两次线程上下文切换的成本。
- 自旋锁加锁失败时,线程进入while循环,系统会忙等待,直到拿到锁(通过cpu提供的CAS函数实现)。
读写锁
读写锁适用于能明确区分读操作和写操作的场景。
其中写锁为独占锁,类似于互斥锁和自旋锁,而读锁是共享锁(不允许写入或修改),可以多个线程同时持有。
因此读多写少时,能发挥优势。并且根据实现不同还进一步分为读优先锁(阻塞写线程直到读线程全完成)和写优先锁。
乐观锁和悲观锁
- 悲观锁:自认为多线程同时修改共享资源的概率比较高,会在访问共享资源前上锁。
- 乐观锁:先修改共享资源,然后提交时核验是否发生冲突,没有则本次操作成功,否则报错并放弃本次操作。
只有冲突概率很低且加锁成本高时会使用到乐观锁。
cas是乐观锁,基于cas实现的自旋锁因为加入了while或者cpu睡眠操作,只有拿到锁才能修改数据。
一个进程可以创建多少个线程
取决于:
- 进程的虚拟内存空间上限
- 系统参数限制
线程崩溃为什么不会导致jvm进程崩溃
因为虚拟机内部定义了信号处理函数,当接收到进程崩溃信号时,会自动转入信号处理函数中来;另一方面如果不做
额外处理,jvm就会产生crash文件,记录虚拟机崩溃的原因。