操作系统基础知识

操作系统基础知识

本篇博文的内容主要介绍操作系统的一些基础知识,这些对于高级编程非常重要,是多线程编程进阶的必备内容。

1. 进程的基本状态:运行、就绪、阻塞

1.1 引起状态转化的事件通常有:

  1. 时间片用完运行转就绪)、
  2. 等待事件(运行转阻塞)、
  3. 等待条件发生(阻塞转就绪)、
  4. 进程调度(就绪转运行);

2. 进程的调度方法有两类:抢占式、非抢占式

3. 在所有调度算法中,短作业优先调度算法的平均等待时间最短;

4. 临界资源:同时只能一个进程使用的资源称为临界资源;

  1. 在进程中,访问临界资源的代码段称为临界区;
  2. 为保证进程互斥访问临界资源,应在进程的临界区之前设置进入去,在临界区后设置退出区;

5. 访问临界资源应遵循的准则

  1. 空闲让进
  2. 忙则等待
  3. 有限等待
  4. 让权等待
  5. 空、忙、有、让

6. 互斥:同类进程需要互斥使用资源;

7. 信号量的物理意义:

  1. 当信号量值大于零时,表示可用资源的数目;
  2. 当信号量值小于零时,其绝对值为在该信号量上等待的进程个数;

8. 任何一个进程在进入临界区之前应调用P操作,退出临界区时应调用V操作;

9. 死锁产生的4个必要条件:(互不请环)

  1. 互斥、
  2. 请求和保持、
  3. 不可剥夺
  4. 环路等待;

10. 不让死锁发生的策略可以分为静态和动态两种,死锁避免属于动态策略。

11. 在可共享系统资源不足时,可能出现死锁。但是,不适当的进程推进顺序也可能产生死锁;

12. 预先静态分配法破坏了死锁产生必要条件中的请求和保持条件,

13. 资源剥夺法和撤销进程的方法破坏了不可剥夺条件,

14. 资源的按序分配策略可以破坏环路等待条件;

15. 执行状态只能由就绪状态转换,而无法有阻塞状态直接转换;

16. 进程创建:

  1. 申请一个空间PCB,并指定唯一的进程标识符PID;
  2. 分配必要的资源;
  3. PCB初始化;
  4. 将PCB插入到就绪队列;

17. 进程撤销:

  1. 从PCB集合中找到被撤销进程的PCB;
  2. 若撤销进程正处于执行状态,则立即停止该进程的执行,设置重新调度标志,以便进程撤销后将处理器分配给其他进程;
  3. 若撤销进程还有子孙进程,还应将该进程的子孙进程予以撤销;
  4. 回收被撤销进程占有的资源,或者归还父进程,或者归还给系统。最后,回收PCB。

18. 阻塞原语(P原语):将进程由执行状态转为阻塞状态;

19. 唤醒原语(V原语):由阻塞状态变为就绪状态;

20. 线程引入的目的:

  1. 使多个程序并发执行,以改善资源利用率和提高系统吞吐量;
  2. 减少程序并发执行所付出的时空开销,使操作系统具有更好的并发性;

21. 进程与线程

  1. 线程是独立调度的基本单位;进程是拥有资源的基本单位;

22. 多线程模型

22.1 多对一模型

将多个用户级线程映射到一个内核级线程上;只要一个用户级线程阻塞,就会导致整个进程阻塞;

22.2 一对一模型

内核级线程与用户级线程一一对应;好处:当一个线程阻塞时,不影响其他线程运行;

22.3 多对多模型

将多个用户级线程映射到多个内核级线程(内核级线程数不多于用户级线程数);这种模型不仅可以使多个用户级线程真正意义上并行执行,而且不会限制用户级线程的数量。用户可以自由创建所需的用户级线程,多个内核级线程根据需要调用用户级线程,当一个用户级线程阻塞时,可以调度执行其他线程。

23. 处理器的三级调度

23.1 高级调度(作业调度)

按照一定的原则从外存上处于后备状态的作业中选择一个或者多个,给它们分配内存、输入输出设备等必要的资源;频率较低,平均几分钟一次;

23.2 中级调度

将处于外存对换区中的具备运行条件的进程调入内存,或者将处于内存中的暂时不能运行的进程交换到外存对换区;主要涉及内存管理与扩充,中级调度可以理解为在幻夜时将页面在外存与内存之间调度;

23.3 低级调度(进程调度)

按照某种策略和方法从就绪队列中选取一个进程,将处理器分配给它;频率很高,一般隔几十毫秒运行一次;

23.4 作业调度为进程被调用做准备,进程调度使进程被调用。换言之,作业调度的结果是为作业创建进程,而进程调度的结果是进程被执行;作业调度次数少,进程调度频率高;有的系统可以不设置作业调度,但进程调度必须有;

24. 衡量调度算法的性能

  1. CPU利用率
  2. 系统吞吐量:单位时间内CPU完成作业的数量;长作业会导致系统吞吐量下降;短作业则相反;
  3. 响应时间
  4. 周转时间:作业从提交至完成的时间间隔,包括等待时间和执行时间;
    a. 平均周转时间:多个作业周转时间的平均值;
    b. 带权周转时间:作业周转时间与运行时间的比;
    c. 平均带权周转时间:平均…

25. 引起进程调度的原因:

  1. 正常结束:当前运行进程运行结束;
  2. 请求资源:当期运行进程因某种原因,比如IO请求、P操作、阻塞原语等,从运行状态进入到阻塞状态;
  3. 执行完系统调度等系统程序后返回用户进程;
  4. 在采用抢占调度方式的系统中,一个具有更高优先级的进程要求使用处理器,则使当前运行进程进入到就绪队列;
  5. 在分时系统中,分配给该进程的时间片已用完;

26. 常见调度算法

26.1 先来先服务(作业调度、进程调度)

常被结合在其他调度策略中使用;

26.2 短作业优先(作业调度、进程调度)

在所有作业同时到达时,SJF调度算法是最佳算法,平均周转时间最短;对长作业不利;

26.3 优先级调度(作业调度、进程调度)

抢占式优先级调度和非抢占式调度

  1. 静态优先级:在创建进程时确定,确定之后在整个进程运行期间不再改变;确定优先级的依据:进程类型(系统进程、用户进程)、作业的资源要求、用户类型和要求;
  2. 动态优先级:创建进程时确定一个优先级,在进程运行过程中再根据情况的变化调整优先级;确定优先级的依据:进程占有CPU时间的长短、就绪进程等待CPU时间的长短来决定;
  3. 在优先级相同的情况下,通常按照先来先服务或者短作业顺序优先的顺序执行;

26.4 时间片轮转(进程调度)

26.5 高响应比优先调度算法(作业调度)

  1. 响应比=作业响应时间/估计运行时间=(作业等待时间+估计运行时间)/估计运行时间

26.6 多级队列调度算法(进程调度)

根据进程的性质或类型,将就绪队列划分为若干个独立的队列,每个进程固定地分属于一个队列。每个队列采用一种调度算法,不同的队列可以采用不同的调度算法。

26.7 多级反馈队列调度算法(进程调度)

27. 互斥实现方法

27.1 方法一

保证互斥访问临界资源,但存在的问题时强制两个进程以交替次序进入临界区,很容易造成资源利用不充分。例如:当进程P0退出临界区后将turn置为1,以便允许进程P1进入临界区,但如果进程P1暂时并未要求访问该临界资源,而P0又想再次访问临界资源,则它无法进入临界区。不能保证实现“空闲让进”准则;

int turn = 0;
P0:
{
        Do{
                while (turn != 0);
                进程P0的临界区代码CS0;
                turn = 1;
                进程P0的其他代码;
        }while (true);
}
P1:
{
        Do{
                while (turn != 1);
                进程P1的临界区代码CS1;
                turn = 0;
                进程P1的其他代码
        }while(true);
}

27.2 方法二

解决了“空闲让进”的问题,但两个进程能够同时进入各自的临界区:当两个进程都为进入临界区时,它们各自的访问标志都为false,若此时刚好两个进程同时都想进入临界区,并且都发现对方的标志值为false(当两进程交替执行了检查语句后,都满足flag[]==false的条件),于是两个进程同时进入了各自的临界区,违背了“忙则等待”。

--“忙”
enum boolean {false,true};//设置数组元素类型
boolean flag[2] = {false,false};//设置标志数组
P0:
{
        Do{
                while (flag[1])//flag[1]为真表示P1在访问临界区,P0等待
                flag[0] = true;
                进程P0的临界区代码CS0;
                flag[0] = false;
                进程P0的其他代码;
        }while (true);
}
P1:
{
        Do{
                while (flag[0])//flag[0]为真表示P0在访问临界区,P0等待
                flag[1] = true;
                进程P1的临界区代码CS0;
                flag[1] = false;
                进程P1的其他代码;
        }while (true);
}

27.3 方法三

可以防止两进程同时进入临界区,但存在两个进程都进不了临界区的问题:当两个进程同时想进入临界区时,它们分别将自己的标志设置为true,并且同时去检查对方的状态,发现对方也要进入临界区,于是都阻塞自己,结果导致两者都无法进入临界区,造成“死等”现象,违背了“有限等待”的准则;

--“有”
enum boolean {false,true};//设置数组元素类型
boolean flag[2] = {false,false};//设置标志数组
P0:
{
        Do{
                flag[0] = true;
                while (flag[1])//flag[1]为真表示P1在访问临界区,P0等待
                进程P0的临界区代码CS0;
                flag[0] = false;
                进程P0的其他代码;
        }while (true);
}
P1:
{
        Do{
                flag[1] = true;
                while (flag[0])//flag[0]为真表示P0在访问临界区,P0等待
                进程P1的临界区代码CS0;
                flag[1] = false;
                进程P1的其他代码;
        }while (true);
}

27.4 方法四

利用flag[]解决临时资源的互斥访问,利用turn解决“饥饿”现象;

enum boolean {false,true};//设置数组元素类型
boolean flag[2] = {false,false};//设置标志数组
int turn;
P0:
{
        Do{
                flag[0] = true;
                turn = 1;//此时p0为进入临界区,仍然允许p1进入临界区
                while (flag[1]&&turn==1)//flag[1]为真表示P1希望访问临界区,turn=1表示p1可以进入临界区,因此p0等待
                进程P0的临界区代码CS0;
                flag[0] = false;
                进程P0的其他代码;
        }while (true);
}
P1:
{
        Do{
                flag[1] = true;
                turn = 0//此时P1未进入临界区,仍然允许P0进入临界区(进入去)
                while (flag[0]&&turn==0)//flag[0]为真表示P0希望访问临界区,turn=0表示p0可以进入临界区,因此p1等待
                进程P1的临界区代码CS0;
                flag[1] = false;
                进程P1的其他代码;
        }while (true);
}

28. 经典同步问题

28.1 先对资源信号量进行P操作,再对互斥信号量进行V操作,否则会导致死锁

28.2 生产者-消费者

semaphore full = 0;
semaphore empty = n;
semaphore metex = 1;
Producer()
{
        while (true)
        {
                Produce an item put in nextp;//nextp为临时缓冲区
                P(empty);//申请一个空缓冲区
                P(mutex);//申请使用缓冲池
                将产品放入缓冲池;
                V(mutex);//缓冲池使用完毕,释放互斥信号量
                V(full);//增加一个满缓冲区
        }
}
Consumer()
{
        while (true)
        {
                P(full);//申请一个满缓冲区
                P(mutex);//申请使用缓冲池
                取出产品;
                V(mutex);//缓冲池使用完毕,释放互斥信号量
                V(empty);//增加一个空缓冲区
                consumer the item in nextc;//消费掉产品
        }
}

28.3 读写者

28.3.1 读者优先算法

semaphore rmutex = 1;//保证对readcount的互斥访问
semaphore mutex = 1;
int readcount = 0;//用于记录读者数量,初值为0
reader()
{
        while (true)
        {
                P(rmutex);
                //如果是第一个读者,要阻止写者进入
                if (readcount==0)
                {
                        P(mutex);
                }
                readcount++;
                V(rmutex);//释放readcount的使用权,允许其他读者使用
                进行读操作;//读不加互斥访问检验,表示可允许同时读
                P(rmutex);
                readcount--;
                if (readcount==0)
                {
                        V(mutex);
                }
                V(rmutex);
        }
}

writer()
{
        while (true)
        {
                //加互斥访问,表示只能有一个写进程写数据
                P(mutex);
                进行写操作;
                V(mutex);
        }
}

28.3.2 公平情况算法(按照到达顺序进行操作)

semaphore rmutex = 1;//用于读者互斥访问readcount
semaphore mutex = 1;
semaphore wmutext = 1;//用于存在写者时禁止新读者进入
int readcount = 0;//用于记录读者数量,初值为0
reader()
{
        while (true)
        {
                P(wmutex);//检测是否有写者存在,无写者时进入
                P(rmutex);
                //如果是第一个读者,要阻止写者进入
                if (readcount==0)
                {
                        P(mutex);
                }
                readcount++;
                V(rmutex);//释放readcount的使用权,允许其他读者使用
                V(wmutex);
                进行读操作;//读不加互斥访问检验,表示可允许同时读
                P(rmutex);
                readcount--;
                if (readcount==0)
                {
                        V(mutex);
                }
                V(rmutex);
        }
}
writer()
{
        while (true)
        {
                P(wmutex);//检测是否有其他写者存在,无写者时进入
                //加互斥访问,表示只能有一个写进程写数据
                P(mutex);
                进行写操作;
                V(mutex);
                V(wmutex);
        }
}

28.3.3 写者优先算法

semaphore rmutex = 1;//用于读者互斥访问readcount
semaphore mutex = 1;
semaphore wmutex = 1;//用于存在写者时禁止新读者进入
semaphore readable = 1;//用于表示当前是否有写者
int readcount = 0;//用于记录读者数量,初值为0
int writecount = 0;//用于记录写者数量,初值为0
reader()
{
        while (true)
        {
                P(readable);//检查是否存在写者,若没有,则占用,进行后续操作
                P(rmutex);
                //如果是第一个读者,要阻止写者进入
                if (readcount==0)
                {
                        P(mutex);
                }
                readcount++;
                V(rmutex);//释放readcount的使用权,允许其他读者使用
                V(readable);
                进行读操作;//读不加互斥访问检验,表示可允许同时读
                P(rmutex);
                readcount--;
                if (readcount==0)
                {
                        V(mutex);
                }
                V(rmutex);
        }
}
writer()
{
        while (true)
        {
                P(wmutex);//检测是否有其他写者存在,无写者时进入
                //若为第一个写者,则阻止后续读者进入
                if (writecount==0)
                {
                P(readable);
                }
                writecount++;
                V(wmutex);
                //加互斥访问,表示只能有一个写进程写数据
                P(mutex);
                进行写操作;
                V(mutex);
                P(wmutex);
                writer--;
                if (writecount==0)
                {
                V(readable);
                }
                V(wmutex);
        }
}

29. 哲学家进餐问题

semaphore fork[5] = {1,1,1,1,1};
philosopher(int i)
{
        while (true)
        {
                思考;
                想吃饭;
                //判断是否为奇数号哲学家,奇数号哲学家先拿左边筷子
                if (i%2!=0)
                {
                        P(fork[i]);
                        P(fork[(i+1)%5]);
                        进餐;
                        V(fork[i]);
                        V(fork[(i+1)%5]);
                }
                //偶数号哲学家先拿右边筷子
                else
                {
                        P(fork[(i + 1) % 5]);
                        P(fork[i]);
                        进餐;
                        V(fork[(i + 1) % 5]);
                        V(fork[i]);
                }
        }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值