2.23 操作系统笔记

时间片轮转

就是给每个进程分配一个时间片,一般设置时10ms,这个能保证每个进程不会太饥饿,但是平均周转时间相对较大,并且会有额外的进程切换的开销

多级反馈队列

也就是有很多个就绪队列,然后不同的队列使用的调度算法不一样,使用比较灵活

实时调度

给每个任务定义了一个开始时间,和截止时间,要在这个区间将这个任务完成

分为了硬时限和软时限

硬时限如果不行,错过会导致严重后果,必须在最坏情况都要完成

软事先不能满足的话降低要求,尽量满足要求就行

同步问题:

现实生活中例子:

冰箱买面包

A想吃面包

去冰箱找  

发现没有 B想吃面包

去买    去冰箱找

      发现没有

      去买

这样就买了重复的面包,如果在计算机内,弄出很多重复的事情将不可估量,然后就考虑做法

这里就牵扯到了计算机的同步,把这些操作都定义为原子操作,那么那个地方就是临界区,同时只能有一个人访问

临界区的实现有三种

1,禁用中断    也就是直接用硬件禁用中断掉,那么无法产生进程切换, 从而达到只有一个访问,但是可能导致其他进程进入饥饿,系统也会停止下来

2,软件操作    使用一些共享变量

3,高级抽象   化为原子操作

信号量

代表资源的数量,有两个操作  P,V

P :代表我申请一个资源,资源-1,如果<0,那么处于等待状态

V:代表释放一个资源,资源+1,如果<=0,代表有人申请了但是处于等待状态,那么我就去唤醒它

int num=3;

P(){
    num--;
    if(num<0) {
         add 当前进入等待队列
        block  堵塞在这等待有资源
    }                
}

V (){
     num++;
     if(num<=0){
         remove  从队列中删除
         wakeup   唤醒一个线程
    }
}    

经典问题: 生产者-消费者

要求:一个桶子可以装n件物品,生产者不断的在制作东西,消费者不断在拿东西,但是对桶子的操作只能同一时间做一个,如果桶子满了,那么生产者需要等待,如果桶子是空的,那么消费者需要等待

int x=1;    //代表互斥信号量,同一时间只能一个人操作桶
int y=0;    //代表现在桶里的东西数量    
int z=n;   // 代表现在桶里剩余空间

product(){   //生产者
       P(z);
       P(x);
        制作东西  
      V(x);
      V(y);      
}

custmer(){
      P(y);
      P(x) ;
      拿东西
      V(x); 
      V(z);
}

管程:

管程也是用于临界区的一种方法,它的操作过程就是,考虑到了当前线程因为一些原因等待时候的情况,这个时候就先放弃临界区的锁,给别的进程先执行,在里面设置有等待队列

Wait():将自己加入等待队列种,然后唤醒一个等待者或者释放管程的互斥访问

Signal():  将等待队列中的一个线程唤醒

管程形式的生产者-消费者问题

Lock lock
int count=0    
int   x,y    //代表东西数和空间数


product(){
     lock-Acquire() ;
     while(count==n){
            notFull.wait(&lock)  //把自己加入等待队列
      }   
       Add c to the buffer;
      count++
       notEmpty.Signal();
      lock->release
}        

cutomer(){
     lock->Acquire()
     while(count==0)
           notEmpty.Wait(&lock);
      remove c from  buffer
      count--
     notFull.Signal
     lock->Release()    
}

哲学家就餐

要求:哲学家就餐也就是n个人n把叉围成一圈,每个人左右两边分别有把叉,然后哲学家每个都能做两件事,思考和就餐,就餐必须拿自己左右两边的叉子才能就餐,怎么有序执行下去

这里明显叉子就是互斥信号量

信号量做法

int cha[5]    //5把叉子

while(1){
      think()//哲学家在思考
      P(cha[i]);
      P(cha[i+1])
      eat()    //就餐
      V(cha[i]);    
      V(cha[i+1])
}        

//如果每个哲学家同时动手拿左边叉子,然后都得不到右边,又无法释放资源,那么处于死锁


while(1){
      think()//哲学家在思考
     P(flag) //  临界区
     P(cha[i]);
     P(cha[i+1])
      eat()    //就餐
      V(cha[i]);    
      V(cha[i+1])
      V(flag);
}        
//这种方法虽然可以,但是加了临界区之后,明明5个人可以同时两个用餐,但是这样变成了一次只能有一个人



while(1){
      think()//哲学家在思考
       if(i%2==0){ 
           P(cha[i]);
           P(cha[i+1])
       }
       else{
            P(cha[i+1]);
            P(cha[i]);
       }
     eat()    //就餐
      V(cha[i]);    
      V(cha[i+1])
}                        
因为第一种方案的死锁只是在都拿左边的时候才会出现,所以只要控制不同人拿的方向不一样就不会出现这种情况了    

读者-写者

要求:读者能够同时有多个进行访问,写只能一个人进行写,读写不能同时进行

死锁概念:

死锁就是进程都处于在申请资源的状态,并且自己也持有对方要的资源

死锁四个必要条件:四个同时成立才会发生死锁

1,互斥:这些资源必须是互斥的,同时只能有一个能够访问

2,请求并保持:自己有资源而且处于申请资源的状态

3,非抢占:只能进程自己运行完自己主动释放资源不能够抢夺

4,循环等待:构成一个环  A->B->C->A   申请的资源都在对方这里

死锁处理

死锁预防:  构成死锁的四个必要条件,只要把其中一个破坏,那么就会预防掉死锁,所以有四种办法

死锁避免:如果当前分配资源会发生死锁,那么申请的资源不会得到分配,然后可以通过银行家算法得出安全序列

死锁检测和恢复

猜你喜欢

转载自www.cnblogs.com/Lis-/p/12353000.html