操作系统进程、线程
1.进程五状态及状态转换图
五状态:新建、就绪、运行、阻塞、退出
五状态进程存在的问题以及解决的办法:
当多个进程竞争资源时,可能导致内存不足,就绪队列满了。Cpu速度比IO速度快很多,可能许多进程都处在阻塞状态,cpu很空闲,利用率低。解决办法,将部分不运行的进程(阻塞进程)的程序和数据(不包括PCB),以腾出内存空间,供其它新进程来使用。
2.进程挂起:进程被交换到外存,状态变为挂起状态
进程挂起的原因:
- 系统负荷较大,内存资源紧张,让其他进程先执行
- 许多进程都处于阻塞状态,cpu很空闲
- 用户或操作系统需求,可能需要将某些进程挂起
进程挂起的特征:
- 不能立刻执行
- 阻塞和挂起没有联系。进程挂起可能是阻塞的,但是及时阻塞进程发生,挂起进程也不能执行。
- 只有挂起挂起进程的进程,使之从挂起状态转变为其它状态
带有进程挂起的状态转换图
3.进程调度与并发
进程是并发的实体和基础,调度则是实现并发机制的手段。
最初,调度的对象是进程,但是现代操作系统都引入了线程这个概念,从而进程蜕变为资源和管理的对象,而线程就成了调度的对象。尽管调度对象发生了变化,但在调度的策略和方法方面并没有发生实质性的变化,加之一些小型操作系统根本就没有线程的概念,因此调度的对象都是以进程为对象的。
所谓进程调度,是指在系统中所有的就绪进程里,按照某种策略确定合适的进程来让处理器运行它。
选择进程调度算法需要需要考虑的原则:
- 资源利用率从(cpu的利用率)
Cpu的利用率 = cpu的有效时间/cpu总的运行时间
Cpu总的运行时间 = cpu有效工作时间 + cpu空闲等待时间
- 吞吐率:单位时间处理的作业数
- 公平性:确保每个进程都能被调度,不会饿死
- 响应时间:交互式进程从提交一个请求命令(进程)到教授到响应时间间隔称为响应时间。
使交互式用户的响应时间尽可能的短,或者尽快处理实时任务,这是分时系统和实时系统衡量调度性能的一个重要指标。
- 周转时间:作业提交给系统开始,到作业完成为止的时间间隔称为响应时间。
调度算法:
- 先来先服务(FCFS)
- 短作业优先算法(shortest job first)
- 优先级调度算法(剥夺式,非剥夺式,静态优先级,动态优先级)
- 时间片轮转调度算法(Round Robin,RR)
- 实际的os调度算法,都是由上述算法综合实现的。基于时间片轮转的优先调度算法,当优先级相同时,采用FCFS。
4.进程与线程的区别
进程:进程是运行着的程序,是系统进行资源分配的一个独立单位。进程之间相互独立,同一进程的线程之间共享数据段(全局变量),但是每个线程有自己的程序计数器和堆栈,支持线程执行的上下文。
线程:线程是进程的一部分,是cpu调度和分派的基本单位。比进程更小的能独立运行的基本单位,线程基本不拥有系统资源,只拥有一点在运行中必不可少的资源(程序计数器,一组寄存器和栈),但是它可以和进程的其它线程共享一个进程所拥有的全部资源。每个线程有自己的堆栈。
5.进程的通信方式
- 管道(pipe):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
- 有名管道(named pipe):有名管道也是半双工的通信方式,但是它允许无亲缘关系进程之间的通信。
- 消息队列(message queue):消息队列是消息的链表,存放在内核中并由消息队列表示符标示。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限制等缺点。
- 共享内存(shared memory):共享内存就是映射一段内被其它进程所访问的内存,共享内存由一个进程创建,但是多个进程都可以访问。共享内存是最快的IPC,它是针对其它进程通信方式运行效率低的而专门设计的。它往往与其它通信机制。如信号量,配合使用,来实现进程间的同步和通信。
- 套接字(socket):套接字也是进程间的通信机制,与其它通信机制不同的是,它可以用于不同机器间的进程通信。
- 信号(signal):信号是一种比较复杂的通信方式,用于通知接受进程进程某个时间已经发生。
- 信号量(semaphore):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁的机制,防止某进程正在访问共享资源时,其它进程也访问该资源。因此它主要作为不同进程或者同一进程之间不同线程之间同步的手段。
6.线程同步
什么情况需要注意线程同步
- 时间的发生的顺序,比如B时间必须要在A时间发生后才能执行。
- 资源共享访,互斥访问,在某个时刻只能有一个线程访问
- 生产者和消费者问题
怎么做线程同步:
- 互斥锁(信号量、互斥变量)
- 读写锁
- 条件变量
7.死锁(deadlock)
死锁:是指两个或两个以上的线程或进程。因争夺资源而造成的互相等待的现象。若无外力作用,他们都将无法推进下去,此时称系统处于死锁状态或产生了死锁,这些永远互相等待的进程称之为死锁进程、线程。
产生死锁的原因:
(1)系统资源不足;(2)进程运行推进的顺序不合适;(3)资源分配不当
产生死锁的四个必要条件:只要系统产生死锁,这四个条件必然成立,只要上述条件之一不满足,就不会发生死锁
(1)互斥条件:一个资源每次只能被一个进程、线程使用
(2)请求与保持:一个进程因请求资源而阻塞时,对已获得资源保持不放
(3)不剥夺条件:进程已获得的资源,在未使用之前,不能强行剥夺
(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源的关系。
处理死锁的四个方式:
(1)仔细地对资源分配,以避免死锁(避免策略)
(2)通过破除死锁的四个必要条件,来预防死锁的发生
有关两种方法:一种是当资源得不到满足时,就必须放弃原先占有的资源;另一种方法是适用于于申请资源的进程优先级比占有该资源的进程优先级高时,如果一个进程申请的资源被其它进程占用,而申请进程的优先级较高,那么就可以强迫占有资源的进程放弃。
(3)检测死锁并且恢复
(4)忽略该问题(PC机中这种问题关系不大)
http://www.cnblogs.com/simonhaninmelbourne/archive/2012/11/24/2786215.html
8.进程的用户态和内核态
一个进程的代码一般包括用户态态代码和内核态代码,当进程执行用户态代码时称进程处于用户态,当进程由于调用系统调用、发成异常或外围中断时就会进入内核中,执行内核代码,称之为处于内核态。
内核创建进程时会创建进.进程控制块和自己的堆栈。一个进程有用户堆栈和内核堆栈,内核低、堆栈的空间指向内核地址空间,用户堆栈指向用户地址空间。Cpu的堆栈指针寄存器,进程运行在不同的状态时,堆栈指针寄存器会指向不同的堆栈。
给进程设置两个栈的原因:
- 安全原因,如果只有一个栈,用户可以随意修改栈内容突破内核安全保护
- 内核的代码和数据是为所有的进程共享的,如果不为每个进程设置对应的内核栈,那么就不能实现不同的进程执行不同的代码。