Process Synchronization

24
Process Synchronization COS 431 Fall, 2000

description

Process Synchronization. COS 431 Fall, 2000. process A. process B. numStudents = 3. Joe. 0 1 2 3 4 5. Mary. interrupt. interrupt. Zelda. Students[num] = “Joey”;. Henry. Joey. Students[num] = “Henry”;. Students. Coordination of Processes. - PowerPoint PPT Presentation

Transcript of Process Synchronization

Page 1: Process Synchronization

Process Synchronization

COS 431

Fall, 2000

Page 2: Process Synchronization

Coordination of Processes

• Often, processes need to synchronize their activities sharing resources when cooperating

• Unfortunately, processes are asynchronous by nature

• Without some means of synchronization: race condition

Students

012345

process A process BnumStudents = 3

Joe

Mary

Zelda

num++;numStudents = num;

num++;numStudents = num;

interrupt

interrupt

num = numStudents;

num = numStudents;

Joey

Students[num] = “Joey”;

Students[num] = “Henry”;

Henry

Page 3: Process Synchronization

Critical Sections/Regions

• Solution: mutual exclusion • Critical regions (critical sections)• Criteria for solution to race conditions:

mutual exclusion make no assumption about speed, num. CPUs no process outside its critical region can block

another no starvation

Page 4: Process Synchronization

A Naïve Approach: Disable Interrupts

• One CPU, if process can disable all interrupts, can guarantee no race conditions

have to disable interrupts from I/O have to disable timer interrupts

• Problem: too much power for user process -- usurps kernel’s power if anything goes wrong -- may hang entire computer! doesn’t work for multiple CPUs

• Kernel needs the ability to do this, though

• In some multithreaded applications, this can be used (e.g., Lisp)

Page 5: Process Synchronization

Another Simple Approach: Locks

• Use a single shared variable as a lock

• Could also be a shared file

• Process looks at variable -- if 0, busy waits, if not set to 0

• Problems May not be atomic Processes may cheat

• Some processors have special instructions (TSL) that help this out, though

Page 6: Process Synchronization

Turn-Taking: Strict Alternation

• Idea:

…non-critical section…

while (turn != my-turn) ; /* busy wait */

critical_section();

turn = next_turn(turn);

…non-critical section…

• What if one of the processes is faster than the others?

• What if a process is I/O bound?

• Processes block others when not in its critical region

Page 7: Process Synchronization

Turn-Taking: Alternation with Interest(Peterson’s Solution)

• Idea -- process declares its interest before it tries for critical region

• Other processes that are interested block if it’s not their turn and if someone else who is interested is in critical section

#define FALSE 0#define TRUE 1#define N 2 /* num processes */

int turnint interested[N];

void enter_region(int process) { int other; other = 1 - process; interested[process] = TRUE; turn = process; while (turn == process && interested[other] == TRUE);}

void leave_region(int process) { interested[process] = FALSE;}

• If only one process ready…• If two processes ready, one in its

critical section…• Two processes both simultaneously

call enter_region...

Page 8: Process Synchronization

“Bakery” Algorithm

• For multiple processes

• Every process that wants to enter critical section given a number

• Lowest number goes first Can’t guarantee that two won’t have same number… …in that case, use tie-breaking convention

BOOLEAN choosing[MAXPROC]; /* picking number or not */int number[MAXPROC]; /* each element corresponds to a process */

void enter(i) { choosing[i] = TRUE; /* we’re picking a number */ number[i] = find_max(number) + 1; /* select next highest number */ choosing[i] = FALSE; /* done */ for (j=0; j<n; j++) { while (choosing[j]) ; /* busy wait if something is choosing number */ /* busy wait till lower proc. with lower number is done */ while ( (number[j] != 0) && customer_lt(j,i) ); }}

void leave(i) { number[i] = 0;}

• What if just one process...?• What if n, with one in critical region...?• What if n try to enter critical region at same time...?

Page 9: Process Synchronization

Hardware Support for Synchronization

• Locks don’t work in general: atomicity multiple processors?

• Some processors : test-and-set-lock (TSL) instruction

• When TSL executed: locks memory bus then:

• sets a register to the value of some memory location (the lock)

• sets the lock to a value meaning “locked” (e.g., 1) then unlocks the memory bus

• Why does this work?

Page 10: Process Synchronization

Mutual Exclusion Using TSL

enter: tsl r1,LOCK ! check LOCK

cmp r1,#0 ! compare old value to 0jnz enter ! if not zero, then it was locked,

! so loopret ! otherwise, return

leave:mov LOCK,#0 ! just clear the lockret

Page 11: Process Synchronization

What’s Wrong with Busy Waiting?

• Wastes processor time

• Priority inversion problem

• Example: Processes busy wait when can’t enter critical region H: high-priority job L: low-priority job Policy: always run high-priority jobs when possible Scenario:

• H: waiting on I/O

• L: runs, enters critical region

• H: I/O completes - context switch to H

• H: tries to enter its critical region What does H do? What does L do?

Page 12: Process Synchronization

Better Idea: Blocking

• Make process not runnable instead of busy waiting

• How is this done?

• When does the process wake up?

• Traditional example: the bounded buffer problem Buffer: storage area with n slots One process is a producer Other is a consumer Buffer full: producer blocks Buffer empty: consumer

• Example: queues

• Relies on producer waking consumer and vice versa

Page 13: Process Synchronization

Producer/Consumer Problem

void producer() { int item; while (TRUE) { item = produce_item(); if (count == N) sleep(); enter_item(item); count++; if (count == 1) wakeup(consumer); }}

#define N 100int count 0;int buffer[N];pid_t producer, consumer;

void consumer() { int item; if (count == 0) sleep(); item = remove_item(); count--; if (count == N-1) wakeup(producer); consume_item(item); }}

int produce_item() { int item; printf(“\nNext item? “); scanf(“%d”,&item); return(item);}

void consume_item(int item) { printf(“item=%d\n”,item);}

Page 14: Process Synchronization

Problems with Sleep/Wakeup

• Signals can be lost due to timing producer sees buffer full, but interrupted before sleep consumer takes something from buffer, sends signal -- which is

lost producer goes to sleep consumer continues taking stuff out, ultimately ==> sleeps both are sleeping!

• Can add some machinery to kernel -- bit in PCB, e.g. -- tells when signal is waiting

• But with > 2 processes, need more bits for the processes ==> arbitrary number of bits needed

Page 15: Process Synchronization

Semaphores

• Motivation: problems with blocking

• Idea: standard way to block processes data structure (semaphores) + two functions defined on them

• Semaphores: enforce mutual exclusion can be used for producer-consumer problems

• Data structure: essentially just an integer -- say, S

• Operations: P(S) -- also known as Down(S) -- decrement S V(S) -- also known as Up(S) -- increment S

• Down(S) and S=0: block caller.

• Up(S) and process blocked on S => unblock it

• Down and Up have to be atomic ==> system calls

Page 16: Process Synchronization

Semaphores

• One way to implement:typedef structure semaphore {

int count = 1;queue procs;};

void Down(semaphore S) {S.count--;if (S.count < 0) {

enqueue(current_proc(),S.procs);block(current_proc());

}}

void Up(semaphore S) {process P;S.count++;if (S.count <= 0) {

P = dequeue(S.queue);wakeup(P);

}}

Page 17: Process Synchronization

Using Semaphores for Mutual Exclusion

• Traditional name for mutual exclusion semaphore is mutex

• Example from the student roster program before:

int num_students;int roster[MAXSTUDENTS];semaphore mutex;...void add_student(int id) {

int currno;Down(mutex);/* critical region starts here */currno = num_students;roster[currno] = id;currno++;num_students = currno;/* end critical region */Up(mutex);return;

}...

Page 18: Process Synchronization

Semaphores and Bounded Buffers

• Single-bounded buffer

• Ex: a print queue

• Something else (we won’t worry about what right now) takes items out of the queue

• What if the queue is full?

• What if the queue is empty?

• Semaphores needed: mutex - a binary semaphore empty -

• counts empty slots

• initialized to number of slots in queue

Page 19: Process Synchronization

Print Queue Example

filename buffer[SLOTS];int next_slot = 0;semaphore mutex, empty;set_count(empty,SLOTS); /* would really be set by

daemon */...void print_file(filename file) {

Down(empty);Down(mutex);/* within critical region now */buffer[next_slot] = file;next_slot++;Up(mutex);

}

• Why is there no Up(empty)?• What if buffer is empty?• What if buffer is full?

Page 20: Process Synchronization

Producer/Consumer Problems and Semaphores

• Complete bounded buffer problem

• Ex.: Message queue: process A writes to it process B reads from it limited size

• Synchronization problem?

• Solution uses three semaphores: mutex, a binary semaphore empty: a counting semaphore -- keeps track of empty slots full: a counting semaphore -- keeps track of full slots

Page 21: Process Synchronization

Producer/Consumer

message buffer[BUFFSIZE];semaphore empty, full, mutex;set_count(empty,BUFFSIZE);set_count(full,0);

void producer() {message msg;while (TRUE) {

msg = compose_message();Down(empty);Down(mutex);/* critical region */put_message(buffer,msg);/* end critical region */Up(mutex);Up(full);

}}

void consumer() {message msg;while (TRUE) {

Down(full);Down(mutex);/* critical region */msg = get_message(buffer);/* end critical region */Up(mutex);Up(empty);use_message(msg);

}}

Page 22: Process Synchronization

Common Problems When Using Semaphores

• Careful not to get carried way with mutex calls! Don’t:void fcn1() {

Down(mutex);fcn2();Up(mutex);

}

void fcn2() {Down(mutex);...Up(mutex);

}

Page 23: Process Synchronization

Problems Using Semaphores

• Careful not to cross semaphore calls:

P1:

Down(S);

Down(T);

...

Up(T);

Up(S);

P2:Down(T);Down(S);

...Up(S);Up(T);

T S

1 1

0

0

-1

blocked-1

blocked

Page 24: Process Synchronization

Semaphores in Unix

• POSIX-compliant Unix: sem_t is the semaphore type sem_wait ==> Down sem_post ==> Up

• Used for threads (or processes, if shared)

• Some Unix systems: only allocate arrays of semaphores semget -- creates a set of semaphores as shared memory objects,

or returns an identifier for such a set semop--perform operations on the semaphore set