Generalize to Messaging Synchronization based on data transfer
(atomic) across a channel Blocking send/receive:
send(destination, &msg); receive(source, &msg);
if no message available, receiver could block alternative, if no message, could return with error code
Mailbox variant mailbox is a bounded buffer of messages attempt to send to full mailbox blocks thread attempt to read from empty mailbox blocks thread
Bounded-Buffer usingMessage Passing Synchronization
void producer() { message pmsg; while (1) { receive(mayproduce, pmsg); pmsg = produceMsg(); send(mayconsume, pmsg); }} /* end producer */
void consumer() { message cmsg; while (1) { receive(mayconsume, cmsg); consumeMsg(cmsg); send(mayproduce, NULL); }} /* end producer */
void main() { /* create 2 mailboxes, init mayproduce w/ N empty messages */ create_mailbox(mayproduce); create_mailbox(mayconsume); for (i = 0; i<CAPACITY; i++) send(mayproduce, NULL); /* create thread for producer()*/ /* create thread for consumer() */}
#define CAPACITY = /* size of mailbox, N */#define NULL = /* empty message */
idea: synchronize using shared mailboxes
Other Classic Synchronization Problems
Sleeping Barber Traffic lights for two lane road through a one
lane tunnel (similar to Vermont Farmers) Monkeys & Gorillas
Monkeys and Gorillas
capacity of rope: 12 monkeys or 1 gorilla
cliff cliff
chasm
rope
1. Sharing a single resource multiple processes (of two or more distinct types)
sharing a single resource; the order of waking up a waiting process can be random
structure of the solution, where t is the type of the process: each process executes
request_resource();
use_resource();
release_resource();
ResourceMonitor.request(t);
type t processuses the resource
ResourceMonitor.release(t);
Reasons for a type t process to wait:
1. conditiont1
2. conditiont2
…
k. conditiontk
Need to declare and initialize shared variables which represent the current “state” of the system so that you can test those values to determine if a particular process should be blocked
Note that one process might have to wait to ensure fairness
monitor ResourceMonitor{
/* declare shared variables representing state *//* declare one condition variable for each
waiting queue (i.e. class of process) */condition aOK; /* type a */condition bOK; /* type b */
… condition tOK; /* type t */
request (type t) { … }release (type t) { … }
/* initialization of shared variables */} // end ResourceMonitor
/* alternatively, could have a separate request/release procedure for each type t */
void request_t() {
/* type “t” process is making this request */
if ( conditiont1 || conditiont2 || … || conditiontk ) {
/* update state – about to block */
tOK.wait();
/* update state – just woke up */
}
/* update state – about to use resource */
}
void release_t() {
/* type “t” process is releasing the resource *//* update state – this process is done using the resource *//* decide if another waiting process should be awakened; if so, who to wake up next */if (wakeup a waiting, type a process)
aOK.signal();else if (wakeup a waiting, type b process)
bOK.signal();… etc. }
}
Monkeys and Gorillas
capacity of rope: 12 monkeys or 1 gorilla
cliff cliff
chasm
rope
MESA semanticsvoid request_t() { /* type “t” process */
while ( conditiont1 || conditiont2 || … || conditiontk ) {/* update state – about to block */tOK.wait();/* update state – just woke up */
}/* update state – about to use resource */
}
void release_t() { /* “t” process is releasing the resource *//* update state – this process is done using the resource *//* wake up all waiting processes */tOK.broadcast(); /* they will awaken within the while loop */
}
2. Sharing a single resource multiple processes sharing a single resource; the
order of waking up a waiting process should be first come, first served
structure of the solution, where N is the size of the process table, 0 <= pid < N is the unique pid of the process
request_resource();
use_resource();
release_resource();
ResourceMonitor2.request(pid);
process pid uses the resource
ResourceMonitor2.release(pid);
monitor ResourceMonitor2{
/* declare shared variables representing state */
declare a FIFO queue of pids;
/* declare one condition variable for each process;
N is size of process table; pids range from 0 to N-1 */
condition self[N];
request (pid) { … }
release (pid) { … }
/* initialization of shared variables */
} // end ResourceMonitor2
void request(int pid) {
/* process pid is making this request */
if ( condition1 || condition2 || … || conditionk ) {
/* update state – about to block */
add pid to FIFO queue
self[pid].wait();
/* update state – just woke up */
}
/* update state – about to use resource */
}
void release(int pid) {
/* process pid is releasing the resource *//* update state – this process is done using the resource */if the queue of pids is not empty { /* the process to wake up next is the first one on the queue */
nextpid = remove from FIFO queue;self[nextpid].signal();
}}
Exercise 6.18
Consider a system consisting of processes p1, p2, … pn, each of which has a unique priority number. Write a monitor that allocates three identical line printers to these processes, using the priority numbers for deciding the order of allocation.
Exercise 6.19
A file is to be shared among different processes, each of which has a unique number. The file can be accessed simultaneously by several processes, subject to the following constraint: the sum of all unique numbers associated with all the processes currently accessing the file must be less than N. Write a monitor to control access to the file.
Exercise 6.22
Write a monitor that implements an alarm clock that enables a calling process to delay itself for a specified number of time units (ticks). You may assume the existance of a real hardware clock that invokes a procedure tick() in your monitor at regular intervals.
Exercise 6.19
A file is to be shared among different processes, each of which has a unique number. The file can be accessed simultaneously by several processes, subject to the following constraint: the sum of all unique numbers associated with all the processes currently accessing the file must be less than N. Write a monitor to control access to the file.
Recap: Methods for Handling Deadlock
Allow deadlock to occur, but…
Ignore it (ostrich algorithm)
Detection and recovery
Ensure that deadlock never occurs, by…
Prevention (negate at least 1 of the 4 necessary conditions for deadlock to occur)
Dynamic avoidance (be careful)
What are the consequences?
May be expensive
Constrains how requests for resources can be made
Processes must give maximum requests in advance
Top Related