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:开关内核的抢先式。