進程同步:指多個進程間互相合作,共同推進
比如大巴車司機和售票員兩個進程:司機必須等到售票員關門後,才能啓動車輛。售票員必須等司機到站停車才能開門。可以通過信號來完成,售票員在關門時發送信號1,司機等待信號1發生後,啓動車輛。司機到站停車發送信號2,售票員等待信號2發生後纔開門。
從紙上到實際:生產者-消費者實例
生產者和消費者共享一塊大小爲10的緩存。生產者每次執行時往緩存裏存1個單位內容,消費者每次從從裏面取一個單位。通過counter來控制兩個進程同步,當計數器等於緩存大小時,表明緩存已滿,並能再往裏放了,因此生產者進程需要阻塞起來(等待),當計數器爲0時說明緩存爲空,此時消費者進程需要阻塞。
因此需要讓進程走走停停來保證多進程合作的合理有序,通過喚醒信號來讓進程從阻塞態到就緒態,如下圖所示
但是當存在多個生產者和消費者時,只有信號並不能解決問題:
- 緩衝區滿以後生產者P1生產一個item放入,會sleep
- 又一個生產者P2生產一個item,會sleep
- 消費者C執行一次循環,counter==BUFFER_SIZE-1,發信號給P1,P1被wakeup
- 消費者C再執行1次循環,counter==BUFFER_SIZE-2,p2不能被喚醒。
此時conuter只能記錄剩餘的空間,並不能記錄有多少進程在睡眠(阻塞)
因此需要有個量記錄有多少進程在等待,從信號——>信號量
sem爲負值表示有多少個P在等待,sem爲正數表示還有多少個緩存空間
sem初值爲緩存空間大小。源碼如下:
semaphore表示信號量結構體,sleep動作就是將進程加入等待隊列。
V(semphore)
{
s.value++;
if(s.value<=0)
wake(s.queue);
}
value爲負,則表示上一次有進程在等待,所以消費者取走一個後,需要從等待隊列裏喚醒一個P進程。