目录
操作系统的五大功能,分别为:作业管理、文件管理、存储管理、输入输出设备管理、进程及处理机管理。
1、进程与线程
1.1、进程模型
进程:具有一定功能的程序在某个数据集的一次运行。进程是系统进行资源调度和分配的独立单元(或者说进程是系统进行资源管理的独立单元)。进程是独立的,有自己的内存空间和上下文环境,无法获取其他进程的存储空间。
1.2、创建进程
有四种主要时间会导致进程创建:
(1)系统初始化
(2)执行了正在运行的进程所调用的进程创建系统调用
(3)用户请求创建一个新进程
(4)一个批处理作业的初始化
1.3、进程终止
终止进程的几种情况:
(1)正常退出
(2)出错退出
(3)严重错误
(4)被其他进程杀死
1.4、进程状态
进程有三种状态:
(1)运行态
(2)就绪态
(3)阻塞态
1.5、进程实现
为了实现进程模型,操作系统维护着一张进程表,该表包含了进程状态的重要信息,包括程序计数器、堆栈指针、内存分配状态、所打开的文件状态等。
1.6、进程同步
进程间同步的主要方法有原子操作、信号量机制、自旋锁、管程、会合、分布式系统等
1.7、线程模型
线程:线程是进程的实体,是在CPU上被调度执行的单位。同一进程的线程可以共享同一内存空间。线程属于进程,当进程退出时,该进程所产生的线程将被强制退出并清除。
1.8、线程实现
(1)在用户空间实现线程
第一种方法是把整个线程包放在用户空间中,内核对线程一无所知。从内核角度考虑,就是按照正常的方式管理,即单线程进程。好处之一,能够在不支持线程的操作系统上实现。可以用函数库实现线程。另外一个优点,允许每个进程有自己定制的调度算法。还有一个优点,有较好的拓展性。
#incldue<pthread.h> //多线程相关操作头文件,可移植众多平台
#include<iostream>
using namespace std;
#define NUMBER_OF_THREADS 10 //线程数
void *print_hello_world(void *tid)
{
/*用于输出进程ID,然后退出*/
cout << "hehho,world!This is " << tid << "th thread!" << endl;
pthread_exit(nullptr); //结束调用的线程
}
int main()
{
//主程序创建10个线程,然后退出
pthread_t THREADS[NUMBER_OF_THREADS];
int status ,i;
for(int i = 0;i < NUMBER_OF_THREADS; i++)
{
cout << "Creating Thread " << i << endl;
status = pthread_creat(&THREADS[i],nullptr,print_hello_world,(void *)i);
if(status != 0)
{
cout <<"THREADS " << i << "return error" << endl;
exit(-1);
}
}
exit(nullptr);
}
确定 取消
线程在一个运行时系统的顶部运行,运行时系统是一个管理线程的过程的集合。对于这类线程,有关线程管理的所有工作都由应用程序完成,内核意识不到线程的存在。在应用程序启动后,操作系统分配给该程序一个进程号,以及其对应的内存空间等资源。应用程序通常先在一个线程中运行,该线程被成为主线程。在其运行的某个时刻,可以通过调用线程库中的函数创建一个在相同进程中运行的新线程。 用户级线程的好处是非常高效,不需要进入内核空间,但并发效率不高。线程在完成运行时,可以把该线程的相关信息保存在线程表中,进而,它可以调用线程调度程序开选择另一个要运行的程序。保存该线程状态的过程和调度程序都是本地过程,所以效率高。用户级线程允许每个进程有自己定制的调度算法。
(2)在内核中实现线程
对于这类线程,有关线程管理的所有工作由内核完成,应用程序没有进行线程管理的代码,只能调用内核线程的接口。内核维护进程及其内部的每个线程,调度也由内核基于线程架构完成。内核级线程的好处是,内核可以将不同线程更好地分配到不同的CPU,以实现真正的并行计算。没有运行时系统,线程表在内核中。
1.9、线程同步
同步:“同”是指的协同,所谓同步,并发的线程在一些关键点上可能需要互相等待与互通信息,这种相互制约的等待与互通信息称为同步。
互斥量 | 互斥量是一种公共资源,在指定时刻,它只能被一个线程占有,而占有它的线程可以反复申请这个互斥量。只有拥有互斥量的线程才能访问公共资源的权限。 |
信号量 | 每个信号量都是公共资源,其值是一个32位计数器。信号量的数据结构是一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源使用情况有关。 |
事件(信号) | 通过通知操作来保持多线程同步,还可以方便实现多线程优先级比较操作。 |
2、进程间通信
进程间通信,需要考虑的三个问题:
1)进程如何将信息传递给另一个进程;
2)多个进程在关键问题中如何不出现交叉;
3)与正确顺序有关
管道 | |
有名管道 | |
信号量 | |
消息队列 | |
信号 | |
共享内存 | |
套接字 |
3、调度
进程的调度算法有哪些?
先来先服务 | |
短作业优先 | |
时间片轮转调度算法 | |
高响应比优先 | |
优先权调度算法 | |
多级队列调度算法 |
4、Windows下的内存是如何管理的?
Windows提供了3种方法来进行内存管理:
(1)虚拟内存,最适合用来管理大型对象或者结构数组
(2)内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行多个进程之间共享数据
(3)内存堆栈,最适合用来管理大量的小对象。
Windows操纵内存可以分两个层面:物理内存和虚拟内存。
其中物理内存由系统管理,不允许应用程序直接访问,应用程序可见的只有一个2G地址空间,而内存分配是通过堆进行的。对于每个进程都有自己的默认堆,当一个堆创建后,就通过虚拟内存操作保留了相应大小的地址块(不占有实际的内存,系统消耗很小)。当在堆上分配一块内存时,系统在堆的地址表里找到一个空闲块(如果找不到,且堆创建属性是可扩充的,则扩充堆大小),为这个空闲块所包含的所有内存页提交物理对象(在物理内存上或硬盘的交换文件上),这时就可以访问这部分地址。提交时,系统将对所有进程的内存统一调配,如果物理内存不够,系统试图把一部分进程暂时不访问的页放入交换文件,以腾出部分物理内存。释放内存时,只在堆中将所在的页解除提交(相应的物理对象被解除),继续保留地址空间。
如果要知道某个地址是否被占用/可不可以访问,只要查询此地址的虚拟内存状态即可。如果是提交,则可以访问。如果仅仅保留,或没保留,则产生一个软件异常。此外,有些内存页可以设置各种属性。如果是只读,向内存写也会产生软件异常。
5、什么是临界区?如何解决冲突?
临界资源:一次仅允许一个线程访问的资源
临界区:每个进程中访问公共资源的代码段,这些公共资源无法同时被多个线程访问。
如何解决冲突?
(1)如果有若干进程要求进入空闲的临界区,一次仅允许一个进程进入;
(2)任何时候,处于临界区内的进程不可多于一个。如已有进程进入自己的临界区,则其它所有试图进入临界区
的进程必须等待;
(3)进入临界区的进程要在有限时间内退出,以便其它进程能及时进入自己的临界区;
(4)如果进程不能进入自己的临界区,则应让出CPU,避免进程出现“忙等”现象。
6、分段和分页
页是信息的物理单位,是为了管理内存的方便划分,对用户是透明的; | 段是信息的逻辑单位,是根据用户的需求划分的,段对用户是可见的; |
页的大小是固定的,有系统决定的; | 段是不固定的,由它的功能决定; |
页向用户提供一维地址; | 段向用户提供二维地址; |
页的保护和共享受到限制 | 段是信息的逻辑单位,便于存储保护和信息共享 |
7、死锁
7.1、什么是死锁?
死锁:在两个或者多个进程中,因争夺资源而造成的一种互相等待的现象,若无外力的情况下,它们都无法进行下去,称系统处于死锁状态。产生的原因:(1)竞争资源;(2)进程推进顺序不当
7.2、死锁产生的必要条件
(1)互斥条件:一个资源一次只能被一个进程使用
(2)请求与保持条件:已经得到某资源的进程可以再请求新的资源
(3)不剥夺条件:已经分配的资源在未使用完之前不能被强行剥夺
(4)环路等待条件:若干进程组成一条环路等待资源
7.3、死锁的处理基本策略和常用方法
解决死锁的方法:
(1)预防死锁
(2)避免死锁
(3)检测死锁
(4)解除死锁
8、进程的上下文切换
上下文切换:并发执行的多进程,是通过处理器在线程中来回切换实现的,操作系统实现这种交错执行的机制称为上下文切换。
当操作系统把控制权从当前进程转交给新进程时,就是进行上下文切换,即保存当前进程的上下文,恢复新进程的上下文,然后将控制权给新进程,新进程从上次停止的地方开始。