OS学习笔记——进程同步与死锁1

进程的同步

对于需要相互合作的进程,执行顺序需要在某些特定时刻进行协调,先达到条件的进程需要等待后到达的进程,此时进程之间存在制约关系。

典型例子是:A负责视频数据采集,B负责把A采集到的数据进行压缩处理。

进程互斥:

当多个进程需要使用相同的资源,而此类资源在任意时刻只能供一个进程使用,获得资源的进程可以继续执行,没有获得资源的进程就需要等待。

典型例子:P1 和 P2都需要使用打印机。必须互斥,否则打印结果交替。


在计算机资源中,有些资源在同一时段只能被一个进程使用,比如打印机。这类资源被叫做临界资源。临界资源可能是硬件可能是软件,通常给首先提出使用申请的进程使用。


生产者和消费者的问题:

操作系统一般提供一个环状缓冲池,用来缓存产品。为了表述缓冲池,可以使用一个数组表示n个(0,1,2,。。。,n-1)缓存区组成的环状缓冲池。在该缓冲池中,使用两个特殊的指针in和out。 in指针用来表示生产者下一个可用的缓冲区位置,out指针用来记录消费者进程可用的下一个满缓冲区。此外设置一个变量counter,用来记录缓冲池中满缓冲区个数,初值为0.


int n;
typedef struct{
	...
}item;

item buffer[n];

0<=in<=n-1;
0<=out<=n-1;
0<=counter<=n;

void producer(){
	boolean bFlag = true;
	do{
		produce an item in nextp;//nextp用来暂存刚生产出来的产品,是缓冲区。
		while(counter == n)
		;
		buffer[in] = nextp;//将生产出来的新产品放入当前空缓冲区
		in = in+1 % n;
		counter = counter + 1;
	}while(bFlag = true)
}

void consumer(){
	boolean bFlag = true;
	do{
		while(counter == 0)
		;
		nextc = buffer[out];//nextc是消费者进程暂存刚取出的产品的缓冲区
		out = out+1 % n;
		counter = counter - 1;
		consume the item in nextc;
	}while(bFlag = true)
}

对于临界资源counter的访问应该是互斥的。

临界区:访问临界资源的代码(critical section)

进入区:进程在进入临界区之前,要对临界资源的使用状况进行查询,如果临界资源处于空闲状态,则该进程可以进入临界区,同时把临界资源状态设置为可使用状态。如果临界资源正在被使用,则该进程不能进入临界区。这段在临界区之前对临界资源使用状态进行检查的代码就叫做进入区。(Entry Section)

退出区:在完成对临界区的访问后,要把临界区访问标志恢复为未被访问的状态,完成这个任务的代码段叫做退出区。

剩余区:进程中除了进入区、临界区、退出区以外都叫做剩余区。


信号量机制

1.整型信号量和P、V操作。

在整型信号量机制中,信号量S是个整型变量,通常被初始化为相应资源的初始数量。除了初始化以外,对信号量S只能通过wait和signal这两个标准的原子操作来访问。所谓原子操作,就是指一旦执行必须全部完成,不能被打断。

void wait(int S)
{
	while(S<=0)
	;
	S = S-1;
}

void signal(int S)
{
	S = S + 1;
}

信号量通常分为互斥信号量和资源信号量


2.记录型信号量

在以上wait操作中,如果信号量S<=0,就会不断地循环测试。进程处于“忙等”状态。这时应该增加一个进程链表用于链接上述等待进程,还有一个代表资源数目的整形变量value,这两者构成记录型信号量。

typedef struct{
	int value;
	struct process *L;
}semaphore;

void wait(semaphore S)
{
	S.value = S.value - 1;
	if(S.value < 0){
		block(S.L);//如果申请不成功,在本次操作之前没有资源,就阻塞本进程,将这个进程加入链表
	}
}

void signal(semaphore S)
{
	S.value = S.value + 1;
	if(S.value <= 0){
		wakeup(S.L);
	}
}

3.AND同步机制
基本思想是:将进程在整个运行过程中需要的所有资源,一次性全部分配给进程,等到进程使用完毕后再一起释放。只要还有一个资源未能分配给进程,其他所有可能为之分配的资源,也不分配给它。

Swait(S1,S2,...Sn)
{
	if(S1>=1 && S2>=1 && ... && Sn>=1)
	{
		for(i = 1;i<=n;i++)
			Si = Si -1;
	}
	else
	{
		将当前进程插入测试过程中发现的第一个资源数量小于等于0的资源Si的阻塞队列中;
		阻塞当前进程。	
	}
}

Ssignal(S1,S2,S3,...Sn)
{
	for(i = 1;i<=n;i++)
	{
		Si++;
		if(资源Si的阻塞队列非空){
			从队首位置取出进程P;
			唤醒进程P;
			if(Swait(P)成功){
				将进程P插入就绪队列;
			}else{
				阻塞进程P;
				将其插入其他资源的阻塞队列
			}
		}
	}
}

4.信号量集
在系统分配资源时,经常设置下限值。如果当前空闲资源数量低于该值时,进程的资源申请将不获批准。




猜你喜欢

转载自blog.csdn.net/Serenity0614/article/details/78764270