1.临界区问题
假设摸个系统中有n个进城,每个进程有一个代码称为临界区,在该区中进程可能会改变同一变量、更新同一文件更新一个表等操作。
临界区问题必须满足一下三个条件:
互斥性,前进性:如果没有进程在临界区内执行切有进程需要进入临界区,那么只有不在剩余区的进程可以参加选择,以确定谁能下一个进入临界区。有限等待。
有两种方法可以处理操作系统馁的临界区问题:抢占内核与非抢占内核。抢占内核允许处于内核模式的进程被抢占而非抢占内核不允许处于内核模式的进程被强占。
2.Peterson算法:
Peterson算法适用于两个进程在临界区与剩余区交替进行
int turn ;
boolean flag[2];
do{
flag[i]=true;
turn=j;
while(flag[j]&&turn=j);
临界区
flag[i]=false;
}while(true);
3.硬件同步:任何临界区问题都需要一个简单地工具----锁
4.信号量
信号量S是个整数变量,除了初始化外,他只能通过两个标准原子操作:wait和signal来访问。这些原子操作原来被称为P(测试)和V(增加)。
wait的定义可以表示为:
war(S){
while(S<=0){
}
S--;
}
signal的定义可以表示为:
signal(S){
S++;
}
在wait和signal操作中,对信号量整型的修改必须不可分的执行,即当有一个进程在修改信号量是不能与一个其他的进程修改同一个信号量。
1)操作系统的信号量通常会分为两种二进制信号量和计数信号量,计数信号量的值域没有限制,而二进制信号量的值域只能为1或者0,因此二进制信号量可以实现互斥。
可以用二进制信号量来处理多线程临界问题,这n个县城共享一个信号量mutex,并初始化为1.每个进程的结构如图所示:
do{
waiting(mutex);
临界区
signal(mutex);
剩余区
}while(TRUE);
计数信号量可以用来控制具有螺杆个实例的某种资源。该信号量初始化为可用资源的数量。当某个进程需要使用该资源时,需要对信号量执行wait操作,当进程释放资源时,需要进行signal操作。当信号量的计数为0时表示所有的资源都被占用。
2)实现
一个阻塞在信号量S上的进程,可以在其他线程执行完signal操作之后被重新执行,该进程的从新执行是通过wakeup函数来执行的,该操作将现场从等待状态切换到就绪后状态。接着,该进程被放入就绪队列中,根据CPU的调度算法不同该线程是否会立即被调度的可能性也是不同的。
为实现这种信号量,定义如下结构:
typedf struct {
int value;
struct process *list;
}semaphore;
wait操作如下定义:
wait(S){
S->value--;
if(S->value<0){
add this process to S->list;
block();//挂起调用他的进程
}
}
signal的操作定义:
signal(S){
S->value++;
if(S->value<=0){
remove a process P from list;
wakep(P);
}
}