經(jīng)典進(jìn)程同步問題2:讀者-寫者問題
來自:http://c.biancheng.net/cpp/html/2601.html
問題描述有讀者和寫者兩組并發(fā)進(jìn)程,共享一個(gè)文件,當(dāng)兩個(gè)或以上的讀進(jìn)程同時(shí)訪問共享數(shù)據(jù)時(shí)不會(huì)產(chǎn)生副作用,但若某個(gè)寫進(jìn)程和其他進(jìn)程(讀進(jìn)程或?qū)戇M(jìn)程)同時(shí)訪問共享數(shù)據(jù)時(shí)則可能導(dǎo)致數(shù)據(jù)不一致的錯(cuò)誤。因此要求:①允許多個(gè)讀者可以同時(shí)對(duì)文件執(zhí)行讀操作;②只允許一個(gè)寫者往文件中寫信息;③任一寫者在完成寫操作之前不允許其他讀者或?qū)懻吖ぷ鳎虎軐懻邎?zhí)行寫操作前,應(yīng)讓已有的讀者和寫者全部退出。 問題分析1) 關(guān)系分析。由題目分析讀者和寫者是互斥的,寫者和寫者也是互斥的,而讀者和讀者不存在互斥問題。
2) 整理思路。兩個(gè)進(jìn)程,即讀者和寫者。寫者是比較簡單的,它和任何進(jìn)程互斥,用互斥信號(hào)量的P操作、V操作即可解決。讀者的問題比較復(fù)雜,它必須實(shí)現(xiàn)與寫者互斥的同時(shí)還要實(shí)現(xiàn)與其他讀者的同步,因此,僅僅簡單的一對(duì)P操作、V操作是無法解決的。那么,在這里用到了一個(gè)計(jì)數(shù)器,用它來判斷當(dāng)前是否有讀者讀文件。當(dāng)有讀者的時(shí)候?qū)懻呤菬o法寫文件的,此時(shí)讀者會(huì)一直占用文件,當(dāng)沒有讀者的時(shí)候?qū)懻卟趴梢詫懳募M瑫r(shí)這里不同讀者對(duì)計(jì)數(shù)器的訪問也應(yīng)該是互斥的。
3) 信號(hào)量設(shè)置。首先設(shè)置信號(hào)量count為計(jì)數(shù)器,用來記錄當(dāng)前讀者數(shù)量,初值為0; 設(shè)置mutex為互斥信號(hào)量,用于保護(hù)更新count變量時(shí)的互斥;設(shè)置互斥信號(hào)量rw用于保證讀者和寫者的互斥訪問。
代碼如下:
int count=0; //用于記錄當(dāng)前的讀者數(shù)量 semaphore mutex=1; //用于保護(hù)更新count變量時(shí)的互斥 semaphore rw=1; //用于保證讀者和寫者互斥地訪問文件 writer () { //寫者進(jìn)程 while (1){ P(rw); // 互斥訪問共享文件 Writing; //寫入 V(rw) ; //釋放共享文件 } } reader () { // 讀者進(jìn)程 while(1){ P (mutex) ; //互斥訪問count變量 if (count==0) //當(dāng)?shù)谝粋€(gè)讀進(jìn)程讀共享文件時(shí) P(rw); //阻止寫進(jìn)程寫 count++; //讀者計(jì)數(shù)器加1 V (mutex) ; //釋放互斥變量count reading; //讀取 P (mutex) ; //互斥訪問count變量 count--; //讀者計(jì)數(shù)器減1 if (count==0) //當(dāng)最后一個(gè)讀進(jìn)程讀完共享文件 V(rw) ; //允許寫進(jìn)程寫 V (mutex) ; //釋放互斥變量 count } }
在上面的算法中,讀進(jìn)程是優(yōu)先的,也就是說,當(dāng)存在讀進(jìn)程時(shí),寫操作將被延遲,并且只要有一個(gè)讀進(jìn)程活躍,隨后而來的讀進(jìn)程都將被允許訪問文件。這樣的方式下,會(huì)導(dǎo)致寫進(jìn)程可能長時(shí)間等待,且存在寫進(jìn)程“餓死”的情況。
如果希望寫進(jìn)程優(yōu)先,即當(dāng)有讀進(jìn)程正在讀共享文件時(shí),有寫進(jìn)程請(qǐng)求訪問,這時(shí)應(yīng)禁止后續(xù)讀進(jìn)程的請(qǐng)求,等待到已在共享文件的讀進(jìn)程執(zhí)行完畢則立即讓寫進(jìn)程執(zhí)行,只有在無寫進(jìn)程執(zhí)行的情況下才允許讀進(jìn)程再次運(yùn)行。為此,增加一個(gè)信號(hào)量并且在上面的程序中 writer()和reader()函數(shù)中各增加一對(duì)PV操作,就可以得到寫進(jìn)程優(yōu)先的解決程序。
int count = 0; //用于記錄當(dāng)前的讀者數(shù)量 semaphore mutex = 1; //用于保護(hù)更新count變量時(shí)的互斥 semaphore rw=1; //用于保證讀者和寫者互斥地訪問文件
semaphore w=1; //用于實(shí)現(xiàn)“寫優(yōu)先”
writer(){
while(1){
P(w); //在無寫進(jìn)程請(qǐng)求時(shí)進(jìn)入
P(rw); //互斥訪問共享文件
writing; //寫入
V(rw); // 釋放共享文件
V(w) ; //恢復(fù)對(duì)共享支件的訪問
}
}
reader () { //讀者進(jìn)程
while (1){
P (w) ; // 在無寫進(jìn)程請(qǐng)求時(shí)進(jìn)入
P (mutex); // 互斥訪問count變量
if (count==0) //當(dāng)?shù)谝粋€(gè)讀進(jìn)程讀共享文件時(shí)
P(rw); //阻止寫進(jìn)程寫
count++; //讀者計(jì)數(shù)器加1
V (mutex) ; //釋放互斥變量count
V(w); //恢復(fù)對(duì)共享文件的訪問
reading; //讀取
P (mutex) ; //互斥訪問count變量
count--; //讀者計(jì)數(shù)器減1
if (count==0) //當(dāng)最后一個(gè)讀進(jìn)程讀完共享文件
V(rw); //允許寫進(jìn)程寫
V (mutex); //釋放互斥變量count
}
}

浙公網(wǎng)安備 33010602011771號(hào)