140 likes | 333 Views
Semaphores. Last Time: Semaphores wait(): n = n - 1; if n < 0 then sleep() (atomic until asleep) signal(): n = n + 1; if n <= 0 then wakeup() (all atomic) Today: More on Semaphores. What does the value of a semaphore mean?. For a semaphore s with value n
E N D
159.302 Semaphores • Last Time: • Semaphores • wait(): n = n - 1; if n < 0 then sleep() (atomic until asleep) • signal(): n = n + 1; if n <= 0 then wakeup() (all atomic) • Today: • More on Semaphores
159.302 What does the value of a semaphore mean? • For a semaphore s with value n • If n is positive then its value is: • The number of wakeups that have been performed on s with out sleeps is n • If n is negative then its value is: • The number of threads sleeping on s is -n
159.302 What are the main uses of semaphores? • Two main uses • For mutual exclusion • mutex=create(1); • .... • wait(mutex) • Critical section • signal(mutex) • ..... For communication • ready=create(0); • .... • Thread1: • wait(ready) • ....Thread2: • signal(ready) • ....
159.302 Semaphores in Windows? • Create: • HANDLE CreateSemaphore(NULL(security attribs),long initval,long maxcount(MAXLONG), char *name(NULL)); • Wait: • WaitForSingleObject(HANDLE h,DWORD timeout(maxlong)); • Signal: • ReleaseSemaphore(handle h,long inccount(1),long * prevcount(NULL));
159.302 Some useful definitions • #define semaphore HANDLE • void wait(semaphore h) { • WaitForSingleObject( h, MAXLONG); • } • void signal(semaphore h) { • ReleaseSemaphore(h,1,NULL); • } • semaphore create(int v) { • return CreateSemaphore(NULL,(long)v, MAXLONG, NULL); • }
159.302 Producer-Consumer int global; // used to hold number being sent semaphore sendsem,receivesem; // for communication int main() { unsigned long id; sendsem=create(0); // initialise to zero receivesem=create(0); CreateThread(NULL,0,producer,0,0,&id); CreateThread(NULL,0,consumer,NULL,0,&id); Sleep(100000); return 0; }
159.302 Producer-Consumer • unsigned long CALLBACK consumer(void *s) { • int val; • while(1) { • wait(sendsem); // wait till producer has made something • val=global; // get it • signal(receivesem); // say we have got it • printf("\t%04d\n",val); • fflush(stdout); • } • } unsigned long CALLBACK producer(void *s) { int val; while(1) { val=rand()%1000+1000*(int)s; // make something global=val; // put it somewhere the consumer can see it printf("%04d\n",val); fflush(stdout); signal(sendsem); // say we have made it wait(receivesem); // wait till consumer has got it } }
159.302 Is this OK? • This will work for one producer but not for many producers. • While the producer is waiting for the consumer it could be producing. • Solution: use a lock instead of receivesem • A lock is a semaphore initialised to 1 and used to control access to a global variable.
159.302 New Main int global; // used to hold number being sent semaphore sendsem,lock; // for communication int main() { unsigned long id; sendsem=create(0); // initialise to zero lock=create(1); CreateThread(NULL,0,producer,0,0,&id); CreateThread(NULL,0,consumer,NULL,0,&id); Sleep(100000); return 0; }
159.302 New Producer-Consumer • unsigned long CALLBACK consumer(void *s) { • int val; • while(1) { • wait(sendsem); // wait till producer has made something • val=global; // get it • signal(lock); // release the lock • printf("\t%04d\n",val); • fflush(stdout); • } • } unsigned long CALLBACK producer(void *s) { int val; while(1) { val=rand()%1000+1000*(int)s; // make something wait(lock); // get the lock global=val; // put val somewhere the consumer can see it printf("%04d\n",val); fflush(stdout); signal(sendsem); // say we have made it } }
159.302 Can we use semaphores for Producer Consumer with a buffer? • Yes (also called the bounded buffer problem) • use two semaphores • thingsinbuffer – initialised to zero • spaceinbuffer – initialised to the buffer size • The consumer waits on thingsinbuffer and signals spaceinbuffer after it has consumed. • The producer waits on spaceinbuffer and signals thingsinbuffer after it has produced.
159.302 Main int buffer[N]; int in=0,out=0; int count=0; semaphore thingsinbuffer,spaceinbuffer,mutex; int main() { unsigned long id; thingsinbuffer=create(0); spaceinbuffer=create(N); mutex=create(1); CreateThread(NULL,0,producer,0,0,&id); CreateThread(NULL,0,consumer,NULL,0,&id); Sleep(100000); return 0; }
159.302 Producer • unsigned long CALLBACK producer(void * s) { • int val; • while(1) { • val=rand()%1000; • Sleep(25); • wait(spaceinbuffer); // wait for space in the buffer • wait(mutex); • buffer[in]=val; • in=(in+1)%N; // critical section • count=count+1; • signal(mutex); • signal(thingsinbuffer);// say there are things in the buffer • } • }
159.302 Consumer • unsigned long CALLBACK consumer(void * s) { • int val; • while(1) { • wait(thingsinbuffer); // wait till something in buffer • wait(mutex); • val=buffer[out]; • out=(out+1)%N; // critical section • count=count-1; • signal(mutex); • signal(spaceinbuffer); // say there is space in the buffer • Sleep(20); • wait(mutex); • printf("%4d %d %d\n",val,count,(in-out+N)%N); • signal(mutex); • } • }