操作系统 --- 哈工大孙志岗70讲总结(26-32)

26
testAndSet指令:取出内存值,设置为True,返回内存原来的值
while循环为临界区
假设lock原来为false,执行原子TestAndSet后为true,返回false会进入临界区。此时另外一个进程访问TestAndSet返回true(保证了不会有两个进程获得锁)
 
许多操作系统将while(TestAndSet(&lock))封装成系统调用。当进程访问临界资源的时候调系统调用,进程加锁成功就进入临界区,否则就一直while循环.
 
27.线程:
创建线程pthread_create();第三个参数是函数指针,线程创建后会执行这个函数。
 
28.
pthread_mutex_lock(&mutex) --- 加互斥锁,线程获得这个锁会返回,否则阻塞
pthreadd_mutex_lock(&mutex)
 
29.
Semaphore(信号量) : 是一个整数,对这个整数赋予两个操作 P() 和 V() ,分别问加一和减一
 
wait() -- +1
wait(S) {
     while S<=0
               ;
     S--;
}
 
  signal() --- -1
signal(S){
     S++;
}
 
wait和signal是原子操作
 
 
Semaphore mutex = 1;
 
Pi(){
     wait(mutex);
     Critical Section;
     signal(mutex);
}
 
传入mutex=1,while不成立,S--然后退出,接着在临界区(Crirital Section)执行代码。最后S++。
当多个进程使用信号量打的时候,只有一个进程能够退出wait(因为wait和signal都是原子操作)
 
计数信号量:一开始mutex不定义成1而是2,这样就能同时有2个进程进入临界区
 
并没有指令直接实现信号量,信号量的实现:
开关中断,TestAndSet
 
代码示例中的实现方式,进入临界区的进程会不断执行死循环(Busy waiting),消耗CPU,也叫自旋锁。
 
解决方法:
 
忙等的时候将进程由运行态切换到等待态。重新定义信号量
 
struct semaphore{
     int value;
     struct process* waiting_list;  //执行PCB的指针,使用指针构造链表,将等待这个信号量的线程都用链表串起来,当进程可以醒来的时候就从链表里拿
}
 
操作系统中避免忙等的思路都是类似,每个设备建一个链表,把所有等待这个设备的PCB链在一起
 
使用两个系统调用:
Block(); //阻塞当前进程
WakeUp(P); //唤醒某个进程
 
/*
//之前是先等再减
wait(S) {
     while S<=0
               ;
     S--;
}
*/
//假设信号量是1,第一个进程value--,不进入if,不阻塞,进入临界区 。第二个进程value--为-1;阻塞
Wait(Semaphore *S){
     S -> value--;
     if(S -> value < 0){     
          add this process to S -> list;
          block();
     }
}
/*
signal(S){
     S++;
}
*/
 
//value为-n表示有n个进程阻塞在这里
Signal(Semaphore *S){
     S ->value++;
     if(S -> value <=0){
          remove a process from S -> list;
          wakeup(P);
     }
}
 
31.
几个线程同步问题:
生产者消费者问题:
两个信号量:
Semaphore mutex 初始为1
Semaphore full 初始为0
Semaphore empty初始为N(缓冲区大小)
 
//生产者     
while(true){
     //produce an item
 
     wait(empty);
     wait(mutex);
     
     //add an item to buffer
 
     signal(mutex);
     signal(full);
}
 
 
//消费者
while(true){
     wait(full);
     wait(mutex);
     //remove an item frm buffer
     signal(mutex);
     signal(empty);
     //consume the removed item
}
 
分析:
mutex作用是保证缓冲区数据的一致性,同时只能有一个线程对共享变量修改。
生产者:
          一开始empty的值是n,生产者wait一个empty(n>0 , if条件不成立),不会阻塞。第n+1个生产者wait的时候会阻塞。
          signal(full),使full++。
          消费者:
          一开始full为0,wait(full)会阻塞。
          同上
 
Reader和Writer问题:writer的同时Read导致数据不一致
 
定义信号量:
Semapohre mutex 初始为 1
Semaphore wrt 初始为 1
整数
Integer readcount 初始为 0 
 
//writer
while(true){
     wait(wrt);
     //writing
     signal(wrt);
}
 
 
//reader
while(true){
     wait(mutex);
     readcount++;
     if(readcount == 1) wait(wrt);
     signal(mutex);
     //reading
     wait(mutex);
     readcount--;
     if(readcount == 0) signal(wrt);
     signal(mutex);
}
 
分析:
mutex的wait和signal是对readcount的保护
reader 读之前需要readcount++;readcount是read的个数
如果readcount==1说明这是第一个读者,会等待 wrt锁。(不允许写)
这时候再来一个读者,readcount++,条件不成立,可以直接读取。
读者读完以后会readcount--,直到readcount为0,没有读进程,才会释放wrt锁;
总的就是第一个read关上了write的门,最后一个read打开write的门。
 
问题:读进程太多导致写进程没有机会执行(对共享内存备份,一个读一个写)
 
哲学家就餐问题
 
32.管程(monitors) --- 一种临界区保护的方法,实现于语言层面。
各种操作系统对同步的支持:
Solaris:
Adaptive mutexes(自适应互斥锁):先自旋几次,不能获得锁就进入等待队列
Windows XP:
开关中断
Linux:开关内核的抢先式。
原文地址:https://www.cnblogs.com/coderlynn/p/8993472.html