210 likes | 416 Views
Cosc 4740. Chapter 6, Part 1 Process Synchronization. Inter-process communications: 2 ways messages passed – requires OS. share memory – doesn’t take much OS work.
E N D
Cosc 4740 Chapter 6, Part 1 Process Synchronization
Inter-process communications: 2 ways • messages passed – requires OS. • share memory – doesn’t take much OS work. • Concurrent access to shared data in “data section” of a multi-thread process, in “shared-memory” of multiple processes, or in a “shared file”
Assuming A = 5, in shared memory of Process A and B. Process A Process B (1) R1 = A (1) R2 = A (2) R1 = R1 + 1 (2) R2 = R2 -1 (3) A = R1 (3) A = R2 • What is the value of A? 4, 5, or 6 • Inconsistency of shared data A
Classic Problem:The producer/consumer problem. Producer Consumer while (true) { while (counter == 0) ; // do nothing and wait nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter--; /* consume the item in nextConsumed } while (true) { while (counter == BUFFER_SIZE); // do nothing and wait /* produce an item and put in nextProduced */ buffer [in] = nextProduced; in = (in + 1) % BUFFER_SIZE; counter++; }
Race Condition • A race condition occurs when you have 2 or more processes sharing resources and what happens depends on the order that they run in. • Why is debugging a race conditions difficult to debug?
Debugging Race Conditions • inconsistent occurrence • It depends on timing and it is intermittent • fixed only by preventing it • We can do this by preventing a block of code from being interrupted during critical times, an Atomic unit of code. • The code sharing memory must be mutually exclusive. • The code that can not be interrupted is the critical section.
Critical Section Problem • Consider system of n processes {p0, p1, … pn-1} • Each process has critical section segment of code • Process may be changing common variables, updating table, writing file, etc • When one process in critical section, no other may be in its critical section • Critical section problem is to design protocol to solve this • Each process must ask permission to enter critical section in entry section, may follow critical section with exit section, then remainder section • Especially challenging with preemptive kernels
Preventing Race Conditions • Ensure no two processes are ever in their shared critical section at the same time. • No assumptions about CPU speeds or numbers. Doesn’t depend on speed of solution • No process running outside it’s critical section may block other processes. • No process should have to wait forever. • Avoid starvation/deadlock – 2 processes starve each other
Solutions: Plan 1 Interrupt solution (could be hardware fix) • Just before critical section, disable all interrupts • The client can stop all others • This is a poor plan since it is not fair. • Then run critical section of code • Finally enable all interrupts • If you forget to re-enable interrupts, you are in big trouble. • Problem: The user code errors can trash the systems • the OS can not turn interrupts back on, because it would interrupt the process.
Attempt #1: Lock a shared variable in the shared resource. Set the lock to 0, means it is open and available Set the lock to 1, means it is locked and unavailable code: Try again: If (lock == 1) goto try again (ie a busy/wait loop) OR while (lock ==1) { }; lock = 1 Critical code section lock = 0 Solutions: Plan 2 software
Problems: • User forgets to reset lock = 0 • The process could be interrupted before setting lock, but after loop!
each waits on other with code int turn = 0; while (true) { // this is a dummy loop while (turn !=0) {}; Critical code section turn = 1; non critical region } // And next code they play back and forth while (true) { //dummy loop to wait while (turn != 1) {}; Critical code section turn = 0; non critical region } Try 2: for 2 processes
This forces them to alternate. • Is this the behavior we want here? • Think about the producer and consumer code? • if it is interrupted before turn =0 • it could block proc 0 even though it is done with its critical region.
Try #3 for 2 processes int turn = 0; int interested[2] = {0}; // when proc wants into critical region it calls enter_region // when it wants out it calls leave_region void enter_region(int process) { int other = 1 – process interested[process] = 1 turn = other while (turn == other && interested[other] == 1) {}; // busy wait } void leave_region (int process) { interested[process] = 0; }
Proc 0 while (true) { enter_region(0); //critical region leave_region(0); //non critical region } Proc 1 while (true) { enter_region(1); //critical region leave_region(1); //non critical region }
Problems (For all solutions so far) • Locks: If not locked An interrupt here can be trouble set lock • We need to have an “atomic” operation – one that can not be interrupted.
“atomic” operation • a hardware solution – TSL – test and set lock • tsl reg, lock // register name, lock it • This is a machine language instruction built into hardware. • Copies lock to reg AND sets lock to 1 (locked)
// this sets lock to 1 after looking, but if • // it was already 1, there is no change. • // if it was “0” then it say “I have have the • // lock” and it sets it to 1 (as always). • enter: tsl reg, lock • if (reg ==1) goto enter • // This means it was already locked when I arrived, so loop • // else It is ok to go to the critical region • critical region • leave: lock = 0;
Have we meet the goals? • No 2 proc. in critical region at once • CPUs or # CPU don’t matter • No prevention of entrance to CR if you are done • No Starvation • well this isn’t fixed. But you can use the “interested” code (try #3)
Busy loop/waiting problem • Wastes CPU time • If scheduler takes into account priority, then low priority process (becomes CPU bound), while other may be high priority • If low priority gets the lock, while the high priority process will have to wait longer while low priority process finishes/release lock.
Q A &