Lecture 13: Producer-Consumer and Semaphores
Review: Mutual Exclusion Solutions Software solution Disabling interrupts Strict alternation Peterson’s solution Hardware solution TSL/XCHG Key issue Busy waiting
Review: Mitigate Busy Waiting /* set lock to non-zero, proceed if it was 0 earlier */ enter_region: TSL Reg, Lock /* set Lock to 1, copy old value of Lock into Reg*/ If (Reg != 0) then /* not the first to set to zero */ { thread_yield() ; /* let somebody else run */ Jump enter_region /* try again */ } return leave_region: Lock = 0
In this lecture sleep() and wakeup() Producer-consumer problem Semaphores
Avoiding Busy Waiting If a process cannot enter critical region, the process calls sleep() to give up CPU. A process wakes up another process using wakeup()
Review: Mutual Exclusion using TSL /* set lock to non-zero, proceed if it was 0 earlier */ enter_region: TSL Reg, Lock /* set Lock to 1, copy old value of Lock into Reg*/ If (Reg != 0) then /* not the first to set to zero */ Jump enter_region /* try again */ return leave_region: Lock = 0
TSL without busy waiting /* set lock to non-zero, proceed if it was 0 earlier */ enter_region: TSL Reg, Lock /* set Lock to 1, copy old value of Lock into Reg*/ If (Reg != 0) then /* not the first to set to zero */ { sleep() Jump enter_region /* try again */ return leave_region: Lock = 0 wakeup(process_id)
Producer – Consumer Problem Mutual exclusion Buffer Full Buffer Empty
How is this solution? No mutual exclusion #define N 100 int count = 0 PRODUCER While (TRUE) { if (count < N){ item = produce_item(); insert_item(item); count = count + 1; } CONSUMER While (TRUE) { if (count > 0){ item = remove_item(); count = count - 1; consume_item(item); }
Using sleep() and wakeup() #define N 100 int count = 0 PRODUCER While (TRUE) { item = produce_item(); if (count == N) sleep(); insert_item(item); count = count + 1; if (count == 1) wakeup(CONSUMER); } CONSUMER While (TRUE) { if (count == 0) sleep(); item = remove_item(); count = count - 1; if (count == N-1) wakeup(PRODUCER); consume_item(item); }
Producer – Consumer Problem Need a way to block till some condition is satisfied Semaphores Condition variables
Semaphore: Interface S: Integer variable down(&S): when (S > 0) S = S – 1; up(&S): S = S + 1; Atomic actions down(&S) block when S =0 up(S) never blocks
Semaphore: Implementation down(&S): If (S=0) then Suspend thread, put into a waiting queue Schedule another thread to run Else decrement S and return up(&S): Increment S If any threads in waiting queue, then release one of them (make it ‘ready’) Both the above are done atomically by disabling interrupts by TSL/XCHG
Producer Consumer using Semaphores #define N 100 int mutex =1; int empty = N; int full = 0 PRODUCER While (TRUE) { item = produce_item(); down(&empty); down(&mutex); insert_item(item); up(&mutex); up(&full); } CONSUMER While (TRUE) { down(&full); down(&mutex); item = remove_item(); up(&mutex); up(&empty); consume_item(item); }
Mutual Exclusion Solutions Software solution Disabling interrupts Strict alternation Peterson’s solution Hardware solution TSL/XCHG
Mutual Exclusion via Semaphore Initialize Semaphore mutex = 1 lock(&mutex)= down(&mutex) unlock(&mutex)= up(&mutex)
Mutual Exclusion via Semaphore lock(&mutex); critical_region(); unlock(&mutex);
Example Web Server can handle only 10 threads at a time Multiple points where threads are being created How to ensure no more than 10 active threads? Semaphore with initial value = 10 down() before Thread creation up() once Thread finishes