系列同步問題:
經典同步問題一——生產者和消費者問題
https://blog.csdn.net/weixin_36465540/article/details/105560002
經典同步問題二——哲學家進餐問題
https://blog.csdn.net/weixin_36465540/article/details/105564907
經典同步問題三——讀者寫者問題
https://blog.csdn.net/weixin_36465540/article/details/105565495
讀者寫者問題
問題描述
多個進程共享存儲區,讀取數據的稱爲讀者,寫數據的稱爲寫者。
條件:
許多讀者可以同時讀取一個文件;
每次只能有一個寫者寫文件。
如果一個寫着在寫文件,不能有讀者讀取文件。
(讀者可以一起讀,寫者之間互斥,讀與寫互斥)
讀者有優先權的解決方案
首先實現讀者可以一起讀,無需控制。
void reader() {
while(1) {
READUNIT();
}
}
void writer() {
while(1) {
WRITEUNIT();
}
}
接下來實現寫者互斥。
Semaphore wsem.value = 1;
void reader() {
while(1) {
READUNIT();
}
}
void writer() {
while(1) {
wait(wsem);
WRITEUNIT();
signal(wsem);
}
}
如何實現讀寫互斥?這裏我們使用一個計數器,當判斷是第一個讀者時,執行wait(wsem),再進入讀者時不執行wait(wsem),這樣讀者可以同時讀。當最後一個讀者離去時,執行signal(wsem)。這樣就實現了讀寫互斥。代碼如下。
但是這種寫法是存在缺陷的,請繼續往下看。
int readcount = 0;
Semaphore wsem.value = 1;
void reader() {
while(1) {
readcount++;
if (readcount == 1)
wait(wsem);
READUNIT();
readcount--;
if (readcount == 0)
signal(wsem);
}
}
void writer() {
while(1) {
wait(wsem);
WRITEUNIT();
signal(wsem);
}
}
這樣寫有一個問題,就是readcount是一個所有讀者共享的數據,對這個數據即有讀的操作,又有寫的操作,且要根據這個值判斷之後的操作,這在多進程的的時候就會存在問題。比如說這樣一種情況,一個進程在readcount++使其變爲1後,其時間片到了,另一個進程又進行了readcount++,這樣wait操作就一直沒有執行。
爲了解決這個問題,再添加一個信號量x.value,將readcount++和readcount–都放入臨界區內,避免競爭條件的產生。這樣才真正解決了讀者寫者問題。
int readcount = 0;
Semaphore wsem.value = 1;
Semaphore x.value = 1;
void reader() {
while(1) {
wait(x);
readcount++;
if (readcount == 1)
wait(wsem);
signal(x);
READUNIT();
wait(x);
readcount--;
if (readcount == 0)
signal(wsem);
signal(x);
}
}
void writer() {
while(1) {
wait(wsem);
WRITEUNIT();
signal(wsem);
}
}
Q:爲什麼上述方案叫讀者有優先權的解決方案?
A:因爲只要能保證一個讀者沒有運行完時,下一個讀者就到了,那麼哪怕中間有寫者想要運行,都需要等待所有的讀者運行完之後,寫者才能運行。