1 / 61

Process Synchronization and Busy Loop Waiting Problem

This chapter discusses the problem of busy loop waiting in process synchronization and introduces the use of sleep() and wakeup() functions. It also explores the producer/consumer or bounded buffer problem and introduces the concept of semaphores as a synchronization tool.

dianek
Download Presentation

Process Synchronization and Busy Loop Waiting Problem

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Cosc 4740 Chapter 6, Part 2 Process Synchronization

  2. 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.

  3. Busy loop fix • Can use sleep() and wakeup() • sleep() blocks the process • it won’t be scheduled • wakeup() moves the sleeping process to the ready list. • If it is blocked for other reasons don’t wake it. • The wakeup() call is issued by another process. The sleeper can not wakeup itself. • Can be setup for a timed event, ie sleep for 1 second, but O/S “Wakes” the process after 1 second.

  4. Producer/Consumer or Bounded buffer problem • 2 processes communication by sharing a fix sized buffer. • (limited way): The producer puts stuff in and the consumer takes stuff out. • Producer  buffer  consumer • It can not just put it in or remove it randomly. The buffer can be full or empty. Must be a balance between producer and consumer.

  5. Buffer: //class An array next: //index variable – next input location // –producer interested in this last: // next output location //– consumer interested in this N: //size-fixed for buffer. Producer() while (true) { produce (item) put_info( buffer[next], item) next = (next+1) mod N } This is a simple minded version. Assumes never full, never empty, no problems Consumer() while (true) { get_item(buffer[last], item) last = (last +1) mod n consume(item) } First attempt

  6. Problems: • what if buffer is full or empty? • If full – don’t put_info • if empty – don’t get_item. • One solution is a busy waiting loop while empty or full.  • OR use sleep() and wakeup()

  7. int count = 0 // global –shared between the processes = # items in buffer array producer () while (true) { produce (item) if (count == N) sleep(); enter_item(item) count++ if (count == 1) wakeup(consumer) } Consumer () while (true) { if (count == 0) sleep() remove_item(item) count --; if (count == N-1) wakeup(producer) consume(item) }

  8. problems: • Consumer codes running reads count and it is zero. Before it goes to sleep, the process is interrupted. • The producer process starts running • puts item in buffer, count = 1 and wakeup consumer. • Which would do nothing, since it was interrupted and already on the ready-queue. • Consumer switched onto the CPU and then goes to sleep. • Producer runs until buffer is full and it too goes to sleep.

  9. The Fix • In 1965 Dykstra invented semaphores to solve these problems.

  10. Quick Review • tsl instruction () • it’s an atomic instruction • allows programmer to set a lock without interruption • problem: busy/waiting wastes CPU • solution: sleep & wakeup • problem: w/ sleep & wakeup – no count of how many proc are sleeping so could put all to sleep

  11. Semaphore • Synchronization tool that does not require busy waiting • Semaphore S – integer variable • contains non-neg integers (>= 0) • Provides a way to count the number of sleep/wakeups invoked • Two standard operations modify S: wait() and signal() • Originally called P() andV()

  12. Semaphore as General Synchronization Tool • Counting semaphore • integer value can range over an unrestricted domain • Binary semaphore • integer value can range only between 0 and 1; can be simpler to implement • Also known as mutex locks • Can implement a counting semaphore S as a binary semaphore • Provides mutual exclusion Semaphore S; // initialized to 1 wait (S); Critical Section signal (S);

  13. Semaphore Implementation • Must guarantee that no two processes can execute wait() and signal() on the same semaphore at the same time • Wait() and Signal() are also critical sections for the variables S. • Note that applications may spend lots of time in critical sections and therefore busy waiting is not a good solution.

  14. Semaphore Implementation (2) • With each semaphore there is an associated waiting queue. Each entry in a waiting queue has two data items: • value (of type integer) • pointer to next record in the list • Two operations: • block – place the process invoking the operation on the appropriate waiting queue. • wakeup – remove one of processes in the waiting queue and place it in the ready queue.

  15. Implementation of wait: wait (S){ S->value--; if (value < 0) { //add this process to //waiting queue for S block(); } } Implementation of signal: Signal (S){ value++; if (value <= 0) { //remove a process P //from the waiting queue //for S wakeup(P); } } Semaphore Implementation (3)

  16. Deadlock and Starvation • Deadlock– two or more processes are waiting indefinitely for an event that can be caused by only one of the waiting processes • Let S and Q be two semaphores initialized to 1 P0P1 wait (S); wait (Q); wait (Q); wait (S); . . . . . . signal (S); signal (Q); signal (Q); signal (S); • Starvation – indefinite blocking. A process may never be removed from the semaphore queue in which it is suspended. • Priority Inversion – Scheduling problem when lower-priority process holds a lock needed by higher-priority process • Solved via priority-inheritance protocol

  17. Classical Problems • Solutions using Semaphores • Bounded-Buffer Problem • Producer-Consumer Problem • Dining-Philosophers Problem • Readers and Writers Problem

  18. Bounded-Buffer Problem • N buffers, each can hold one item • Semaphore mutex initialized to the value 1 • Semaphore full initialized to the value 0 • Semaphore empty initialized to the value N.

  19. Bounded Buffer Problem (Cont.) • The structure of the producer process while (true) {// produce an item produce(item); wait (empty); //check if buffer is full, if yes, block wait (mutex); //enter CR to add item. // add the item to the buffer signal (mutex); //leave CR system. signal (full); //increment full }

  20. Bounded Buffer Problem (2) • The structure of the consumer process while (true) { wait (full); //check to see if buffer is “full” //start w/full =0, so it blocks if there is nothing yet. wait (mutex); //Enter CR // remove an item from buffer signal (mutex); //leave CR signal (empty); //increment empty // consume the removed item }

  21. Bounded Buffer Problem (3) • The producer block should be removed when at least 1 item is removed • The consumer must tell the producer by a signal(s) operation. • Recall that semaphores keep a count of wait() & signal() calls and are atomic functions.

  22. Dining-Philosophers Problem • 5 philosophers • 5 forks • Each philosopher • (1) eat • (2) thinks • Catch: If a philosopher wants to each it needs two forks

  23. philosopher(i) while(1) { think() pick up 2 forks eat() put down forks } Problem: To eat, a philosopher needs 2 forks 2 neighbors can not eat at the same time. can not pick up more than 1 fork at a time. So 1 philosopher might starve!

  24. With No locking. philosopher(i) left = I; right = (I+1) mod 5; while(1) { think() pick_fork[right] =1 pick_fork [left ] =1 eat () put_fork [right]=0 put_fork [ left] =0 }

  25. With Semaphores semaphore S[5] = {1,1,1,1,1} // init to 1 while (1) { think(); Wait(S[left]); Wait(S[right]); eat () Signal(s[left]); Signal(s[right]); }

  26. Now when a fork is not avail, the philosopher will block. • Problem: • If all philosophers pick up left fork 1st, then no right forks are available. • We need to be able to pick up both forks or none, so we need a semaphore to do this: make picking up forks atomic.

  27. Philosphers(i) { take_forks(i) { Wait(mutex); while(1) { Wait(S[left]); think(); Wait(S[right]); take_forks(i); Signal(mutex); eat(); } put_forks(i); } } put_forks(i) { Wait(mutex); Signal(S[left]); Signal(S(right]); So what problems arise? Signal(mutex); }

  28. So what problems arise? • If philosophers is blocked on a right or left fork, he will be deadlocked, because no other process can put_forks, since it is in it’s critical section! • There are other methods that can fix this problem.

  29. Readers/writers problem Two types of processes • readers – reads information from the database • writers – write to the database • And we want concurrent access to the database.

  30. problem 1 • 2 writers try to modify the db at same time. • constraint: At must 1 writer should access the database at any time • problem 2 • a reader is attempting to read an entry while it is in the process of being modified and could read an intermediate value (or wrong value). • Constraint: A writer and reader cannot access the database at the same time.

  31. try #1 semaphore db = 1; writer () { P(db); // protect db from other writers and readers modify database V(db); } readers () P(db); read database V(db); } • no problem with constraints but it excludes other readers

  32. try #2 • we want to allow multiple readers, but no readers w/ writers v = 0; db =1; writer() reader() P(db) if (v==1) v = 1; read (database) modify(database) v = 0; V(db)

  33. Problem: v is not protected. When you access v, it should be w/in a semaphore • Why? • Also readers can already be in the database, when the writer enters. Writer is not blocked by readers. • P(db) in reader, will also block readers too. • We want a P(db) block on writers put on the by the 1st reader only and removed by last reader!

  34. semaphore mutex int rc =0; //reader count  reader() P(mutex) // Protect rc if (rc ==0) { P(db); } rc ++; V(mutex); read database; P(mutex) rc – if (rc ==0) { V(db); } V(mutex); writer() P(db); modify database V(db); Try #3

  35. This solution allows multi readers • no writer/reader combo, but writer will starve • may never get a chance if readers keep arriving. Writer unblocked only when all readers done. • So what is a fair solution? • We need to alternate between writers and readers. • You must maintain a count of # of readers reading and you must maintain a flag when writer arrives. • Can be done with higher level primitives to make it easier.

  36. Problems with Semaphores • Incorrect use of semaphore operations: • signal (mutex) …. wait (mutex) • wait (mutex) … wait (mutex) • Omitting of wait (mutex) or signal (mutex) (or both) • Deadlock and starvation

  37. higher level primitives • There are two primitives that well look at: • Conditional Critical Region (CCR) • Monitor

  38. Conditional Critical Region • Explicitly designates a section of the program as critical. • a mechanism to specify variables to be protected in critical region. • conditions under which a critical section may be entered

  39. designated critical section  region //always assoc w/ resource variable protection  resource resource R1name: v1, v2, … Vn R2name: v1, v2, …, Vn region R1name when B do S end • // B: condition of entry: boolean expression • // S: statement list • // region statements are scattered through the program. Region statements can be nested, but CAUTION: deadlocks become very likely.

  40. Example • Unisex bathroom problem • single bathroom • 2 processes types: male and female • constraints • No male & Female in BR at same time, multi-male ok, multi-female ok.

  41. resource bathroom: fc=0, mc=0; //protected variables (male count = mc, etc) • //Note male and female solution is the same, expect switch mc and fc male() region bathroom when fc = 0 do mc ++; use bathroom mc --; end

  42. Problem • The region statement at any one time is only for only one process to be in the region, so multi-male (multi-female) constraints fails

  43. Try #2 males() region bathroom when fc==0 do mc++ end use bathroom region bathroom when true do mc-- end

  44. Allows concurrency. Second part, protect, so only one process accessing mc at the same time (mutual exclusion). • problem: starvation

  45. Dinning Philosophers (again) resource eat: forks[5] ={0,0,0,0,0} philosopher(i) //assume left and right are defined think(); region eat when ((fork[left] ==0)&&(fork[right]==0) do fork[left] =1; fork[right]=1; end eating(); region eat when true do fork[left] =0; fork[right]=0; end

  46. Monitors • A monitor is a collection of procedures and variables and data structures • Processes can access these variables only by invoking the procedures in the monitor • At most 1 process can be active at any time in the monitor. This provides mutual exclusion • Unlike CCR’s the code is NOT scattered. It is in the monitor • condition variables provided: 2 operations defined • wait(c): causes the process to block on C – and the processes leaves the monitor • signal(c): unblocks one of the processes. The unblocked process runs immediately.

  47. Monitors • Only one process may be active within the monitor at a time monitor monitor-name { // shared variable declarations procedure P1 (…) { …. } … procedure Pn (…) {……} Initialization code ( ….) { … } … } }

  48. Schematic view of a Monitor

  49. 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)that invoked x.wait ()

  50. Monitor with Condition Variables

More Related