vault backup: 2025-03-17 10:04:23
This commit is contained in:
parent
e9f44190a2
commit
8e1ea33ab8
3 changed files with 18 additions and 11 deletions
159
Concurrent Systems/notes/4b - Monitors.md
Normal file
159
Concurrent Systems/notes/4b - Monitors.md
Normal file
|
@ -0,0 +1,159 @@
|
|||
Semaphores are hard to use in practice because quite low level Monitors provide an easier definition of concurrent objects at the level of Prog. Lang.
|
||||
|
||||
It guarantees mutual exclusion.
|
||||
|
||||
Inter-process synchronization is done through *conditions*, which are objects that provide the following operations:
|
||||
- ***wait*:** the invoking process suspends, enters into the condition's queue, and releases the mutex on the monitor
|
||||
- ***signal*:** if no process is in the condition's queue, the nothing happens. Otherwise
|
||||
- reactivates the first suspended process, suspends the signaling process that however has a priority to re-enter the monitor (*Hoare semantics*)
|
||||
- completes its task and the first process in the condition's queue has the priority to enter the monitor (after that the signaling one terminates or suspends) (*Mesa semantics*).
|
||||
|
||||
#### A very typical use: Rendez-vous
|
||||
A soon as a process arrives at a barrier it needs to suspend and wait for every other process to reach the barrier.
|
||||
|
||||
```
|
||||
monitor RNDV :=
|
||||
cnt ∈ {0,…,m} init at 0
|
||||
condition B
|
||||
operation barrier() :=
|
||||
cnt++
|
||||
if cnt < m then
|
||||
B.wait()
|
||||
else
|
||||
cnt <- 0
|
||||
B.signal()
|
||||
return
|
||||
```
|
||||
The last process wakes up one of the others, then he wakes up another one etc...
|
||||
Of course, `signal()` will have no effect on the last process who calls it.
|
||||
|
||||
#### Monitor implementation through semaphores
|
||||
*Hoare semantics*
|
||||
|
||||
- A semaphore MUTEX init at 1 (to guarantee mutex in the monitor)
|
||||
- For every condition C, a semaphore SEMC init at 0 and an integer $N_{C}$ init at 0 (to store and count the number of suspended processes on the given condition)
|
||||
- A semaphore PRIO init at 0 and an integer $N_{PR}$ init at 0 (to store and count the number of processes that have performed a signal, and so have priority to re-enter the monitor)
|
||||
|
||||
Every monitor operation starts with `MUTEX.down()` and ends with `if NPR > 0 then PRIO.up() else MUTEX.up()`
|
||||
|
||||
```
|
||||
C.wait() :=
|
||||
NC++
|
||||
if NPR > 0 then
|
||||
PRIO.up()
|
||||
else
|
||||
MUTEX.up()
|
||||
SEMC.down()
|
||||
NC--
|
||||
return
|
||||
|
||||
C.signal() :=
|
||||
if NC > 0 then
|
||||
NPR++
|
||||
SEMC.up()
|
||||
PRIO.down()
|
||||
NPR--
|
||||
```
|
||||
p.s. The wait **always** suspends, even if there is only a process.
|
||||
|
||||
#### Readers/Writers problem, strong priority to Readers
|
||||
```
|
||||
monitor RW_READERS :=
|
||||
AR, WR, AW, WW init at 0
|
||||
condition CR, CW
|
||||
|
||||
operation begin_read() :=
|
||||
WR++
|
||||
if AW != 0 then
|
||||
CR.wait()
|
||||
CR.signal()
|
||||
AR++
|
||||
WR--
|
||||
|
||||
operation end_read() :=
|
||||
AR--
|
||||
if AR + WR = 0 then
|
||||
CW.signal()
|
||||
|
||||
operation begin_write() :=
|
||||
if (AR+WR != 0 or AW != 0) then
|
||||
CW.wait()
|
||||
AW++
|
||||
|
||||
operation end_write() :=
|
||||
AW--
|
||||
if WR > 0 then
|
||||
CR.signal()
|
||||
else
|
||||
CW.signal()
|
||||
|
||||
```
|
||||
|
||||
#### Readers/Writers problem, strong priority to Writers
|
||||
```
|
||||
monitor RW_READERS :=
|
||||
AR, WR, AW, WW init at 0
|
||||
condition CR, CW
|
||||
|
||||
operation begin_read() :=
|
||||
if WW + AW != 0 then
|
||||
CR.wait()
|
||||
CR.signal()
|
||||
AR++
|
||||
|
||||
operation end_read() :=
|
||||
AR--
|
||||
if AR = 0 then
|
||||
CW.signal()
|
||||
|
||||
operation begin_write() :=
|
||||
WW++
|
||||
if (AR + AW != 0) then
|
||||
CW.wait()
|
||||
AW++
|
||||
WW--
|
||||
|
||||
operation end_write() :=
|
||||
AW--
|
||||
if WW > 0 then
|
||||
CW.signal()
|
||||
else
|
||||
CR.signal()
|
||||
```
|
||||
|
||||
#### Readers/Writers problem, a fair solution
|
||||
- after a write, all waiting readers are enabled
|
||||
- during a read, new readers must wait if writers are waiting
|
||||
```
|
||||
monitor RW_READERS :=
|
||||
AR, WR, AW, WW init at 0
|
||||
condition CR, CW
|
||||
|
||||
operation begin_read() :=
|
||||
WR++
|
||||
if WW + AW != 0 then
|
||||
CR.wait()
|
||||
CR.signal()
|
||||
AR++
|
||||
WR--
|
||||
|
||||
operation end_read() :=
|
||||
AR--
|
||||
if AR = 0 then
|
||||
CW.signal()
|
||||
|
||||
operation begin_write() :=
|
||||
WW++
|
||||
if (AR + AW != 0) then
|
||||
CW.wait()
|
||||
AW++
|
||||
WW--
|
||||
|
||||
operation end_write() :=
|
||||
AW--
|
||||
if WR > 0 then
|
||||
CR.signal()
|
||||
else
|
||||
CW.signal()
|
||||
```
|
||||
This way nobody gets starved forever.
|
Loading…
Add table
Add a link
Reference in a new issue