`
isiqi
  • 浏览: 16484228 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

操作系统之进程同步

阅读更多

进程同步
前面我们提到了协作进程,协作进程就是会影响其他进程,即会共享逻辑地址空间,即共享内存系统,对于这种情况,很有可能会同时访问同一变量导致出错。还有一个是独立进程,是不会影响的进程。消息传递的协作进程不会导致进程同步问题。

所以我们这章讨论的是基于共享内存的协作进程。


竞争条件:多个进程并发访问同一数据切数据的结果与执行进程先后有关。
临界区:临界区只能允许一个进程执行。
进程分为进入区,临界区,退出区,剩余区。进入区需要有表示请求进入临界区的代码,退出区要有表示退出临界区的代码。
临界区问题:有空则进,无空则等,有限等待。

在操作系统内,执行内核代码也会遇到临界区问题。
在执行内核代码时,分为抢占内核和非抢占内核。
非抢占内核:在一个进程进入内核模式后,不允许另一个进程也进入。 因此不会导致竞争条件。

抢占内核因为允许在内核中执行的进程被抢占,所以会发生数据不一致。

对于SMP结构更难控制,因为进程在不同处理器上。

Peterson算法:用于处理临界区问题。 Peterson算法的宗旨是“谦让”,因为一开始都先把机会留给另一个人。
do
{
flag[i]=true;
turn=j;
while(flag[j]&&turn==j);
...
flag[i]=false;
}while(TRUE);

flag表示想要进入临界区,turn是能进入临界区。

前面讲的是通过软件进行同步,后面开始讲硬件同步。
对于单处理器,在修改共享变量时需要禁止中断出现,从而实现了非抢占内核。

对于多处理器,采用前面通知禁止中断则不可行,因为需要将禁止中断发送给全部的处理器,速度慢。因此需要一个机器指令,能够原子地执行。
原子地:不可中断。

书上直接讲TestAndSet的例子显得太突然,不好上手,所以查了下资料,逐步讲起。

do{

while(turn!=i);

临界区

turn=j;

剩余区

}while(true);

这个例子的问题是在退出区turn=j显得太突兀,因为不满足有空则进的原则。如果j不进,那就谁都进不了了。

下面一个例子是添加了bool变量。

do{

flag[i]=true;

while(flag[j]); //问题在于如果flag[j]没进去,也在等待,那么i就一直不能进,因此也没解决有空则等的条件。

临界区

flag[i]=false;

剩余区

}while(true);


bool TestAndSet(bool *target)
{
bool* r=*target;
*target=true;
return r;
}
do
{
while(TestAndSet(&lock));
...
lock=false;
}while(TRUE);
分析:开始时,lock为false,返回false,则开始进入临界区,因为表明没人加锁;而如果lock为true,则说明有人在临界区,则不能进入。

缺点:虽然能解决互斥和前进。但是没有解决有限等待。

void swap(bool*a,bool *b)
{
bool temp=*a;
*a=*b;
*b=temp;
}
do
{
key=TRUE;
while(KEY==true)
swap(&key,&lock);
...
lock=false;

}while(true);
分析:开始lock为false,key为true,一开始因为临界区没人,所以交换后key为false,则进入临界区。

其实以上两者思想有事一样的,如果一开始lock为false,则都会跳出循环。但是他们不能满足有限等待,因为多进程时,没有一个界定来表明什么时候能进入临界区。缺点和上面一样。

//以下实现了有限等待,因为会像循环队列一样一轮一轮看,如果waiting[j]==true且j!=i 即j在等待,则waiting[j]=false;如果j==i, 则lock=false;

-----------------------

do
{
waiting[i]=true;
key=TRUE;
while(waiting[i]&&key)
key=TestAndSet(&lock);
waiting[i]=false;
....
j=(i+1)%n;
while(j!=i&&!waiting[j])
j=(j+1)%n;
if(j==i)
lock=false;
else
waiting[j]=false;
}while(TRUE);


信号量(即资源,用整数大小来代表多少)可以用来同步,信号量规定为s,表示所拥有的资源的个数,有原子操作wait(S),signal(S)表示--和++。

信号量分为:计数信号量和二进制信号量。
当进程需要使用资源,则调用wait。
但是信号量有个缺点,就是忙等。忙等的意思是在一个进程进入临界区,其他进程必须要在while循环中不断循环,只有当一个进程出临界区时才能进入。而浪费CPU的时间,因此解决方案是当一个进程进入临界区,则可以用自旋锁spinlock,这样就可以让其他进程进入其他临界区,充分利用CPU时间。
wait函数当资源用完时,就把此进程放入等待队列,利用CPU调度调用另一个进程。

为了确定两个进程的访问特定数据的顺序
p1
signal(S);
-------------------

p2

wait(S);
-------------------

且将S初始化为0,则一定要p1先执行。

信号量的缺点是忙等待(但可能也是优点,因为上下文切换可能消耗更多的资源)因为wait操作造成的,这种称为自旋锁,因为一直在自旋。。。
自旋锁的方案是当A进程调用wait时,如果资源已用完,则阻塞进入该信号量的等待队列,如果什么时候signal又有资源了,则wakeup把他唤醒,进入内存中的就绪队列。

struct semaphore

{

int value;

struct Process *list; //等待队列,signal会从等待队列中取出一个进程唤醒

};

wait(semaphore *S)

{

s->value--;

if(s->value<0){

block(); //进入等待队列,并重新调入

}

}

signal(semaphore *S)

{

S->value++;

if(s->value>0) {

wakeup(p); //从等待队列中唤醒一个进程

}

}

多处理器可以使用自旋锁来实现同步,即一个进程在一个处理器上运行,一个进程在另一个处理器自旋。

执行PV操作的要求只有一个!就是wait和signal必须是原子的。

在单和多处理器(SMP)都需要禁止中断来解决原子。

死锁:多个进程对于信号量可能产生死锁,死锁就是A进程为了wait(S)信号量必须等待B进程signal(S),而B进程为了wait(T)必须等待A进程signal(T),从而两方都处于死锁状态。

而信号量的等待队列的LIFO实现方法可能会使得无限阻塞或饥饿。即一直不能执行。

经典同步问题:

1.有限缓冲问题:即生产者消费者问题

//empty是空的buffer的个数,full是满的buffer的个数 mutex是互斥锁

//生产者
do
{
//produce
wait(empty);
wait(mutex);

signal(mutex);
signal(full);
}while(true);
//消费者
do
{
wait(full);
wait(mutex);

signal(mutex);
signal(empty);
}while(true);
2.读者写者问题

读者写者问题的要求是可以有多个读者,一个写者。
读者写者有第一读者写者问题和第二读者写者问题。
第一读者写者问题:读者不需要保持等待除非一个写者已经进入临界区。
第二读者写者问题:一旦写者开始等待,那么写者会尽可能快的执行写操作,读操作不能占先。
//已知mutex,wrt都是二进制信号量,初始化为1,readcount是读者的个数
//写者
do
{
wait(wrt);
临界区
signal(wrt);
}while(true);

//读者
do
{
wait(mutex);
readcount++;
if(readcount==1)
wait(wrt);
signal(mutex);

wait(mutex);
readcount--;
if(readcount==0)
signal(wrt);
signal(mutex);
}while(true);

当然比如java就提供了读写锁,可以方便进行进程同步,也可以解决读者写者问题,但是开销较大。
3.哲学家进餐问题

semaphore chopstick[5];
do
{
wait(chopstick[i]);
wait(chopstick[(i+1)%5]);
//eat
signal(chopstick[i]);
signal(chopstick[(i+1)%5]);
//think
}while(true);
这种方法会导致死锁,因为当哲学家都执行第一条语句时,都不能执行下一条语句。舍弃。

解决方法:
1.最多允许4个哲学家同时坐桌子上。。
2.只有两只筷子都能拿起时才拿。
3.奇数哲学家先拿左边筷子,接着拿右边筷子,而偶数哲学家相反。

信号量还是不够安全,因为可能会写错。所以引入管程(monitor)。

管程默认就是只能有一个进程在管程内活动,所以不用人为编写同步代码。

定义condition类型变量可定义额外的同步机制。对于条件变量只有wait和signal操作。

wait只意味着进程block,signal只意味着重新启动进程。condition变量类似于信号量,有一个等待队列。用于挂起进程。

基于管程的哲学家进餐问题实现:

monitor dp
{
enum{THINKING,HUNGRY,EATING}state[5];
condition self[5];

void pickup(int i)
{
state[i]=HUNGRY;
test(i);
if(state[i]!=EATING)
self.wait();
}

void putdown(int i)
{
state[i]=THINKING;
test((i+4)%5);
test((i+1)%5);
}

void test(int i)
{
if(state[(i+4)%5]!=EATING)&&state[i]==HUNGRY&&state[(i+1)%5]!=EATING)
{
state[i]==EATING;
self[i].signal();
}
}

initialization_code() //初始化代码,必有
{
for(int i=0;i<5;i++)
state[i]=THINKING;
}
}

//记住:管程的操作默认是互斥的。

下面讨论的问题是condition variable 的等待队列重启进程的选择方式。

通常用条件队列,经常的优先级如下设定:

进程事先说明资源分配的最大需求,管程优先分配给最短分配请求的进程。

管程的高级操作的正确使用也是要注意的。

分享到:
评论

相关推荐

    操作系统实验四 进程同步实验

    操作系统实验四的进程同步实验是深入理解并发协作进程同步与互斥的重要实践环节。通过这个实验,学生可以直观地观察到并发进程如何进行同步与互斥操作,从而增强对这两个核心概念的认识。实验报告旨在分析经典进程...

    操作系统实验之进程同步

    总结来说,"操作系统实验之进程同步"不仅让我们了解了理论知识,更让我们通过动手实践掌握了如何在实际场景中运用这些知识。这是一次宝贵的学习经历,使我们对于操作系统内核的运行机制有了更深的理解,也为未来解决...

    操作系统进程同步

    ### 操作系统进程同步知识点详解 #### 进程同步概览 进程同步是操作系统中一个核心概念,旨在解决多进程间资源竞争的问题,确保多个进程能够有序地访问共享资源,防止数据不一致性和死锁等问题的发生。进程同步机制...

    进程同步(操作系统实验三,带实验报告哦,亲)

    操作系统中的进程同步是多线程或并发执行时保持系统稳定性和正确性的重要概念。这个实验主要是基于北邮操作系统课程的第三次实验,目的是让学生通过实践理解并掌握进程同步的基本原理和方法。实验使用C语言编程,并...

    操作系统_进程同步算法习题精选.ppt

    操作系统_进程同步算法习题精选.ppt

    山东大学 操作系统 实验四 进程同步实验

    操作系统是计算机科学中的核心课程,而进程同步是操作系统中至关重要的一部分。在山东大学的操作系统实验四中,学生们将深入探索这一主题,通过实践加深对进程同步的理解和应用。实验的目标是让学生掌握如何在多线程...

    操作系统-进程同步的实现

    在多任务操作系统中,进程同步是一个至关重要的概念,它确保了多个并发执行的进程能够有效地共享资源,避免数据冲突和死锁,从而提高系统效率。本压缩包文件包含的"实操一:进程同步"提供了实现进程同步的源代码,...

    操作系统实验-信号量机制实现进程同步

    在多道程序设计中,进程同步是操作系统中的一个重要概念,它涉及到多个并发进程间的协调和通信,确保它们能正确、有序地访问共享资源,避免数据竞争和死锁等问题的发生。 信号量机制是实现进程同步的一种有效工具,...

    操作系统进程同步与通信

    操作系统中的进程同步与通信是确保多进程环境下的正确运行和高效协作的重要机制。在操作系统引入进程后,由于进程的异步执行特性,可能导致程序执行的结果出现不确定性,这被称为不可再现性。为了解决这个问题,引入...

    操作系统进程同步和互斥的实验报告

    操作系统进程同步和互斥是操作系统中至关重要的概念,它们确保了多进程或多线程环境下的资源有效管理和安全访问。本实验报告详细介绍了如何通过编程实现这一机制,并以生产者-消费者问题为实例进行演示。 实验的...

    操作系统-进程同步习题答案.pdf

    操作系统-进程同步习题答案.pdf

    操作系统\ 进程同步.pdf

    本文将深入探讨操作系统进程同步的基本概念、临界区问题、同步硬件、信号量、管程以及经典同步问题的解决方案,特别关注在Solaris 2和Windows 2000系统中的应用。 ### 背景 在多道程序环境下,多个进程可能同时...

    操作系统实验 进程的同步

    西安电子科技大学操作系统实验 进程的同步 c++编程 西电操作系统实验 编程语言c++

    操作系统实验报告_进程同步与互斥.doc

    操作系统实验报告《进程同步与互斥》实验的主要目的是掌握基本的进程同步与互斥算法,了解生产者-消费者问题,并学习使用 Windows 2000/XP 中基本的同步对象,掌握相关 API 的使用方法。实验中,设计了一个控制台...

    操作系统中进程同步与互斥的实现.pdf

    从给定文件中提取到的这些知识点,是操作系统进程管理中的核心内容,对于理解操作系统的工作原理及其进程调度、资源管理等方面都有着重要的意义。学习进程同步与互斥不仅有助于解决实际工作中遇到的并发控制问题,还...

    进程同步实验(山东大学操作系统实验)

    操作系统是计算机科学中的核心课程之一,而进程同步是操作系统中非常关键的概念,它涉及到多任务环境下的并发控制和资源协调。在本实验“进程同步实验(山东大学操作系统实验)”中,我们将深入探讨这一主题,并通过...

    操作系统实验三进程同步

    ### 操作系统实验三:进程同步 #### 实验目的与要求 本次实验旨在帮助学生深入理解进程/线程同步的概念及应用方法,并学会利用进程/线程同步技术解决实际问题。具体目标包括: 1. **理解进程/线程同步原理**:通过...

    操作系统实验报告——线程与进程同步

    操作系统实验报告——线程与进程同步,主要探讨了在Linux环境下如何实现进程和线程的同步,以解决经典的生产者-消费者问题。该实验旨在帮助学生掌握操作系统提供的同步机制,并深化对经典同步问题的理解。 实验内容...

Global site tag (gtag.js) - Google Analytics