(轉)很有借鑒意義!讀者寫者問題--使用信號量的讀者優先與寫者優先程序分析


轉自http://www.linuxso.com/linuxbiancheng/13098.html

 

千萬要注意:readcount,writecount要設成共享變量(因為是進程),要不然可能會導致死鎖

 

所謂誰誰優先的問題,我認為主要體現在以下兩點中:

1.當低優先級進程(線程)獲得臨界區時,高優先級進程能很快從低優先級的進程中搶得訪問權。

2.當高優先級的進程獲得臨界區訪問權時,低優先級得等到高優先級全部訪問完的空閑時間才能搶得訪問權。

這兩點中, 第一點一定得要,不然無法體現出優先的意思 。

第二點可以根據程序的需要決定。

 

程序摘自:《操作系統精髓與設計原理》

 

/* program readersandwriters*/
//讀者優先,經過我修改了一點
int readcount = 0;
semaphore x = 1,z = 1, wsem = 1;
void reader()
{
	while(true){
		semWait(x);
		readcount ++ ;
		if(readcount == 1)
			semWait(wsem);
		semSignal(x);
		
		READUNIT();//讀數據

		semWait(x);
		readcount --;
		if(readcount == 0)
			semSignal(wsem);
		semSignal(x);
	}
}
void writer()
{
	while(true){
		semWait(z);//自己加的,不過這樣降低了寫操作的效率,但滿足了以上2點。去除z信號后,就只滿足第1點,可以自己分析分析
		semWait(wsem);
		WRITEUNIT();//寫數據
		semSignal(wsem);
		semSignal(z);
	}
}

 

 

程序中semWait 就是指信號量P 操作, semSignal 就是指V

首先明白一點 如果某一信號初始值為1 ,且在一個函數中是P,V操作是成對出現 ,那么這個信號量就是用來起互斥作用!

信號量x ,是用來保證readCount 自加自減操作和if條件語句操作的原子性。

來分析下為什么這個程序是讀優先呢?

1.考慮下這種情況:如果讀者已經獲得臨界區的訪問權,那么當讀者連續不斷時(即中間間隔小),也就是說當一個進程讀完前,另一個進程也進入到了臨界區。 此時的話,任一時間在臨界區中的寫進程者會大於一 。 即使來了寫進程,也只能有一個寫者阻塞在wsem信號中,其余全阻塞在z信號中。。。直到某一時刻,無讀者在臨界區時,才有機會寫臨界區。

2.在考慮一種情況:寫進程已經獲得了臨界區的訪問權,且寫進程也很密集。 此時讀進程能不能優先得到訪問權而不用等到寫進程全部訪問完呢?

答案是能。  寫進程很多,那么一次又只能有一個寫進程訪問臨界區。則其余的寫進程都會在z信號中阻塞,排隊且。 如果讀進程也想訪問了,讀進程就會在wsem信號中阻塞排隊即只有讀進程會在wsem中阻塞排隊。   注意:當此時的寫進程一旦完成訪問臨界區WRITEUNIT . 下一句semSignal(wsem) , 好, 此時阻塞在wsem隊列中的讀進程就搶得到臨界區的訪問權。。

綜上所述:在讀者優先的程序中:寫進程只有等待無讀者訪問臨界區的時刻,才能得到訪問權 ; 讀進程在任意時候都可以得到訪問權。

阻塞在wsem隊列中最多只有一個寫者 ,其余的寫者阻塞在z信號中。  wsem隊列中當然最多可能有有限個寫者(因為寫者能有很短的時候內得到訪問權)

 

 

//寫者優先

 

/*program readersandwriters*/
//寫者優先
int readcount , writecount;
semaphore x = 1, y = 1, z = 1, wsem = 1 , rsem = 1;
void reader()
{
	while(true){
		semWait(z);//z信號用來保證阻塞在rsem信號中排隊的讀者至多只有一個。其余的阻塞在z上。
			semWait(rsem);
				semWait(x);//保證下面3句操作的原子性
					readcount ++;//在這里,當有寫者出現時,由於rsem的阻塞,readcount的值不會大於1
					if(readcount == i)//i應該是1才對
						semWait(wsem);//為了讓真正執行READUNIT()時沒人打擾
				semSignal(x);
			semSignal(rsem);//寫者搶占訪問權的時機!
		semSignal(z);

		READUNIT();

		semWait(x);
			readcount --; //由於上面readcount只能為1,所以下面語句必然執行
			if(readcount == 0)
				semSignal(wsem);
		semSignal(x);		
	}
}

void writer()
{
	while(true){
		semWait(y);
			writecount ++;
			if(writecount == 1)
				semWait(rsem);//第一個寫者阻塞地方
		semSignal(y);

		semWait(wsem);//為了讓真正執行WRITEUNIT()時沒人打擾

			WRITEUNIT();
		semSignal(wsem);

		semWait(y);
			writecount --;
			if(writecount == 0)//最后一個寫者才釋放rsem,這時讀者才有機會訪問,讀者也才有機會semWait(wsem)                                              ,否則在沒機會semWait(wsem),寫者當然可以繼續
				semSignal(rsem);
		semSignal(y);
	}
}


同前面一樣, y是用來保護寫者中對writecount操作的原子性。

 

1.當讀者獲得了訪問臨界區的權利時,且讀者進程訪問的很密集時(即很多讀者都需要訪問),寫者如何搶得訪問權。

當讀者獲得訪問權時即有一個進程正在執行READUINT操作時。和上一個讀者優先程序中的寫者差不多,如果沒有寫者,那么讀者就能一個接一個到達臨界區訪問。但是因為READUINT操作前由於有z信號和rsem信號的互斥作用。使得讀者一個只有一個通過這一段代碼,其余的者阻塞在z信號中。進入臨界區時是依次進入的(但出來不一定是先進先出) 。 一旦此時來了一個寫者,他就會阻塞在rsem信號中。等會此時的讀者剛一執行完semSignal(rsem)時,那么寫者就得到rsem信號可以繼續執行了。然后寫者就只用等待讀者中已經進入臨界區的出來就能執行了。  

2.當寫者獲得臨界區的訪問權時,讀者只能等到臨界區空閑時才能得到臨界區訪問權。

因為當寫者獲得臨界區時,所有的讀者都會阻塞在z信號和rsem信號中。   而只有最后一個寫者訪問完臨界區時,才會semSignal(rsem), 使得阻塞在rsem中唯一的讀者獲得臨界區訪問權。

 

z信號的作用是 當讀者獲得權限時, 此時來的寫者不用等待他前面所有的讀者都訪問完才訪問 。  因為z信號使得在rsem信號隊列中至多只有一個讀者阻塞

 

 

 

轉載注明出處

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM