200 likes | 218 Views
Explore concepts of process synchronization, condition variables, and memory-mapped I/O in advanced operating systems. Discusses atomic transactions, storage, and memory usage. Design questions for implementing file server processes included.
E N D
Advanced Operating Systems - Fall 2009Lecture 7 – February 2, 2009 • Dan C. Marinescu • Email: dcm@cs.ucf.edu • Office: HEC 439 B. • Office hours: M, Wd 3 – 4:30.
Last, Current, Next Lecture • Last time: • Process synchronization • Today • Discussion of a problem regarding threads and I/O. • More about condition variables and monitors • Discussion of a problem about condition variables and monitors. • Next time: • Atomic transactions
Dictionary • Monitor: programming language construct for controlled access to critical sections. • Transaction (general): an agreement, communication, or movement carried out between separate entities involving the exchange of information, goods, services, or money. • Database transaction: a unit of work performed by a database management system in a coherent and reliable way, independent of other transactions. • Atomic transaction: a group of database operations that either all occur, or none occurs. Atomicity prevents updates to the database occurring only partially. • Storage: volatile, non-volatile, stable Can the information be recovered in case of failure?
Dictionary (cont’d) • Condition variables: indicate an event and have no value. One cannot store a value into nor retrieve a value from a condition variable. If a thread must wait for an event to occur, that thread waits on the corresponding condition variable. Two operations can be performed on a condition variable: Wait(v) and Signal(v). • Memory-mapped file: a segment of virtual memory which has been assigned a direct byte-for-byte correlation with some portion of a file or file-like resource. This resource could be a file physically present on-disk, or a device, shared memory object, or other resource that the OS can reference through a file descriptor. • Memory-mapped I/O uses the same address bus to address both memory and I/O devices, and the CPU instructions used to access the memory are also used for accessing devices. Regions of CPU's addressable space are reserved for I/O.
Dictionary (cont’d) • Condition variables: indicate an event and have no value. One cannot store a value into nor retrieve a value from a condition variable. If a thread must wait for an event to occur, that thread waits on the corresponding condition variable. Two operations can be performed on a condition variable: Wait(v) and Signal(v). • Memory-mapped file: a segment of virtual memory which has been assigned a direct byte-for-byte correlation with some portion of a file or file-like resource. This resource could be a file physically present on-disk, or a device, shared memory object, or other resource that the OS can reference through a file descriptor. • Memory-mapped I/O uses the same address bus to address both memory and I/O devices, and the CPU instructions used to access the memory are also used for accessing devices. Regions of CPU's addressable space are reserved for I/O.
Problem • We wish to separate the logical from physical reading/writing to a file and implement a file server process which receives from a user process requests to • read to files and sends back the data • write files and writes the data to the file • Two possible implementations: • The server maintains a cache of recently used files in memory reading and writing from/cache whenever possible. How should we use multithreading in this case: (a) one thread per process or (b) multiple threads per process. • The server maintains a large buffer space and allows a user process to read and write asynchronously to file buffers.
Design questions • Why separate logical from physical I/O operations? • What do we gain and what is the price to pay? • Can we use the concept for all types of I/O (e.g., disk and networking?) • What are the main features of each one of the two alternatives? • Can a user process use multiple files? How many? • Could it support multiple user processes? How many? • What are the limitations of each approach. • Sketch the design for each of the two alternatives. • Which one will be easier to implement and why? • Which one is more effective at run time and why? • Which one of the two options for the first alternative would you consider and why? Are both options feasible? • Compare these two alternative with a memory-mapped file. • Discuss memory mapped I/O. Is it related to the methods above?
Monitors • Programming languages constructs. • The compiler handles calls to monitors differently than other calls. • Only one process may be active within the monitor at a time monitor monitor-name { // shared variable declarations procedure P1 (…) { …. } … procedure Pn (…) {……} Initialization code ( ….) { … } … } }
Blocking a process when it cannot proceed • Condition variables • condition x, y; • Two operations on a condition variable: • x.wait () – a process that invokes the operation is suspended. • x.signal () –resumes one of processes(if any)thatinvoked x.wait ()
A Producer-Consumer Monitor monitor ProducerConsumer; condition full, empty; integer count; procedure enter; if count = N thenwait(full); add_Item; count++; if count = 1 thensignal(empty); end; procedure remove; if count = 0 thenwait(empty); remove_Item; count--; if count = N-1 thensignal(full); end; count=0; end monitor;
A Producer-Consumer Monitor (cont’d) procedure producer; begin while true do begin produce_Item; ProducerConsumer_enter; end end procedure producer; begin while true do begin ProducerConsumer_remove; consume_Item; end end
Solution to Dining Philosophers monitor DP { enum { THINKING; HUNGRY, EATING) state [5] ; condition self [5]; void pickup (int i) { state[i] = HUNGRY; test(i); if (state[i] != EATING) self [i].wait; } void putdown (int i) { state[i] = THINKING; // test left and right neighbors test((i + 4) modulo 5); test((i + 1) modulo 5); }
Dining Philosophers (cont’d) void test (int i) { if ( (state[(i + 4) modulo 5] != EATING) && (state[i] == HUNGRY) && (state[(i + 1) modulo 5] != EATING) ) { state[i] = EATING ; self[i].signal () ; } } initialization_code() { for (int i = 0; i < 5; i++) state[i] = THINKING; } }
Dining Philosophers (cont’d) • Each philosopher I invokes theoperations pickup() and putdown() in the following sequence: dp.pickup (i) EAT dp.putdown (i)
Monitor Implementation Using Semaphores • Variables semaphore mutex; // (initially = 1) semaphore next; // (initially = 0) int next-count = 0; • Each procedure F will be replaced by wait(mutex); … body of F; … if (next-count > 0) signal(next) else signal(mutex); • Mutual exclusion within a monitor is ensured.
Monitor Implementation • For each condition variable x, we have: semaphore x-sem; // (initially = 0) int x-count = 0; • The operation x.waitcan be implemented as: x-count++; if (next-count > 0) signal(next); else signal(mutex); wait(x-sem); x-count--;
Monitor Implementation • The operation x.signal can be implemented as: if (x-count > 0) { next-count++; signal(x-sem); wait(next); next-count--; }
Problem for discussion • Monitors use condition variables and two operations: WAIT(v) and SIGNAL(v). Why not use a single primitive with a Boolean predicate p: WAITUNTIL(p). For example: WAITUNTIL (v1 < 0 or v2 + v3 > n) • How would you implementWAITUNTIL?