操作系统:经典进程同步问题 之 生产者-消费者问题、读者-写者问题、哲学家进餐问题
?
在進程同步中,經典的同步問題有:生產者-消費者問題、讀者-寫者問題、哲學家進餐問題。
一、生產者與消費者問題:
問題描述:使用一個緩沖區來保存物品,只有緩沖區沒有滿,生產者才可以放入物品;只有緩沖區不為空,消費者才可以拿走物品。
1、使用信號量實現生產者-消費者問題:
down?: 如果信號量大于 0 ,執行 -1 操作;如果信號量等于 0,進程睡眠,等待信號量大于 0;
up?:對信號量執行 +1 操作,喚醒睡眠的進程讓其完成 down 操作。
因為緩沖區屬于臨界資源,因此需要使用一個互斥量 mutex 來控制對緩沖區的互斥訪問。
為了同步生產者和消費者的行為,需要記錄緩沖區中物品的數量。數量可以使用信號量來進行統計,這里需要使用兩個信號量:empty 記錄空緩沖區的數量,full 記錄滿緩沖區的數量。其中,empty 信號量是在生產者進程中使用,當 empty 不為 0 時,生產者才可以放入物品;full 信號量是在消費者進程中使用,當 full 信號量不為 0 時,消費者才可以取走物品。
注意,不能先對緩沖區進行加鎖,再測試信號量。也就是說,不能先執行 down(mutex) 再執行 down(empty)。如果這么做了,那么可能會出現這種情況:生產者對緩沖區加鎖后,執行 down(empty) 操作,發現 empty = 0,此時生產者睡眠。消費者不能進入臨界區,因為生產者對緩沖區加鎖了,消費者就無法執行 up(empty) 操作,empty 永遠都為 0,導致生產者永遠等待下,不會釋放鎖,消費者因此也會永遠等待下去。
#define N 100 typedef int semaphore; semaphore mutex = 1; semaphore empty = N; semaphore full = 0;void producer() {while(TRUE) {int item = produce_item();down(&empty);down(&mutex);insert_item(item);up(&mutex);up(&full);} }void consumer() {while(TRUE) {down(&full);down(&mutex);int item = remove_item();consume_item(item);up(&mutex);up(&empty);} }2、使用管程實現生產者-消費者問題:
?// 管程
?monitor ProducerConsumer
? ? condition full, empty;
? ? integer count := 0;
? ? condition c;
? ? procedure insert(item: integer);
? ? begin
? ? ? ? if count = N then wait(full);
? ? ? ? insert_item(item);
? ? ? ? count := count + 1;
? ? ? ? if count = 1 then signal(empty);
? ? end;
? ? function remove: integer;
? ? begin
? ? ? ? if count = 0 then wait(empty);
? ? ? ? remove = remove_item;
? ? ? ? count := count - 1;
? ? ? ? if count = N -1 then signal(full);
? ? end;
end monitor;
// 生產者客戶端
procedure producer
begin
? ? while true do
? ? begin
? ? ? ? item = produce_item;
? ? ? ? ProducerConsumer.insert(item);
? ? end
end;
// 消費者客戶端
procedure consumer
begin
? ? while true do
? ? begin
? ? ? ? item = ProducerConsumer.remove;
? ? ? ? consume_item(item);
? ? end
end;
?
二、讀者-寫者問題:
允許多個進程同時對數據進行讀操作,但是不允許讀和寫以及寫和寫操作同時發生。
一個整型變量 count 記錄在對數據進行讀操作的進程數量,一個互斥量 count_mutex 用于對 count 加鎖,一個互斥量 data_mutex 用于對讀寫的數據加鎖。
typedef int semaphore; semaphore count_mutex = 1; semaphore data_mutex = 1; int count = 0;void reader() {while(TRUE) {down(&count_mutex);count++;if(count == 1) down(&data_mutex); // 第一個讀者需要對數據進行加鎖,防止寫進程訪問up(&count_mutex);read();down(&count_mutex);count--;if(count == 0) up(&data_mutex);up(&count_mutex);} }void writer() {while(TRUE) {down(&data_mutex);write();up(&data_mutex);} }?
三、哲學家進餐問題:
五個哲學家圍著一張圓桌,每個哲學家面前放著食物。哲學家的生活有兩種交替活動:吃飯以及思考。當一個哲學家吃飯時,需要先拿起自己左右兩邊的兩根筷子,并且一次只能拿起一根筷子。
下面是一種錯誤的解法,考慮到如果所有哲學家同時拿起左手邊的筷子,那么就無法拿起右手邊的筷子,造成死鎖。
#define N 5void philosopher(int i) {while(TRUE) {think();take(i); // 拿起左邊的筷子take((i+1)%N); // 拿起右邊的筷子eat();put(i);put((i+1)%N);} }為了防止死鎖的發生,可以設置兩個條件:
- 必須同時拿起左右兩根筷子;
- 只有在兩個鄰居都沒有進餐的情況下才允許進餐。
?
?
文章轉自:https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/%E8%AE%A1%E7%AE%97%E6%9C%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8
總結
以上是生活随笔為你收集整理的操作系统:经典进程同步问题 之 生产者-消费者问题、读者-写者问题、哲学家进餐问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Maven(二):常用命令、依赖管理
- 下一篇: java信息管理系统总结_java实现科