To solve the Too Much Milk problem, mom and dad decide to lock the fridge. There is only one key to open the lock, and the one who gets the key can check the fridge. That is to say, if mom gets the key and checks the fridge, dad cannot open the fridge until mom releases the key. Mom will release the key until she ensures there is milk in fridge. In mom_sol.c and dad_sol.c, we use semaphore to implement the key. Read the following programs and run them to see what will happen.
Note that programs using the POSIX semaphores API must be compiled with -pthread to link against the library. So you need to compile these two programs like this:
/*mom_sol.c*/#include<fcntl.h>#include<semaphore.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/stat.h>#include<unistd.h>intmain(int argc,char*argv[]) {int fd;int VALUE =1;sem_t*mutex;// If semaphore with name "mutex" does not exist, then create it with VALUE mutex =sem_open("mutex", O_CREAT,0666, VALUE);printf("Mom comes home.\n");// wait on semaphore "mutex" and decrease it by 1sem_wait(mutex);printf("Mom checks the fridge.\n");// If file "fridge" does not exist, then create it, you can see manual pages for// details fd =open("fridge", O_CREAT | O_RDWR | O_APPEND,0777);//"fridge" is emptyif (lseek(fd,0, SEEK_END)==0) {printf("Mom goes to buy milk...\n");sleep(2);write(fd,"milk ",5);printf("Mom puts milk in fridge and leaves.\n");// there is milk in "fridge" alreadyif (lseek(fd,0, SEEK_END)>5)printf("What a waste of food! The fridge can not hold so much milk!\n"); } else {printf("Mom closes the fridge and leaves.\n"); }// close file "fridge"close(fd);// add semaphore "mutex" by 1sem_post(mutex);// Before exit, you need to close semaphore and unlink it, when all processes have// finished using the semaphore, it can be removed from the system using sem_unlinksem_close(mutex);sem_unlink("mutex");return0;}
/*dad_sol.c*/#include<fcntl.h>#include<semaphore.h>#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/stat.h>#include<unistd.h>intmain(int argc,char*argv[]) {int fd;int VALUE =1;sem_t*mutex; mutex =sem_open("mutex", O_CREAT,0666, VALUE);printf("Dad comes home.\n");sleep(rand() %2+1);sem_wait(mutex);printf("Dad checks the fridge.\n"); fd =open("fridge", O_CREAT | O_RDWR | O_APPEND,0777);if (lseek(fd,0, SEEK_END)==0) {printf("Dad goes to buy milk...\n");sleep(rand() %2+1);write(fd,"milk ",5);printf("Dad puts milk in fridge and leaves.\n");if (lseek(fd,0, SEEK_END)>5)printf("What a waste of food! The fridge can not hold so much milk!\n"); } else {printf("Dad closes the fridge and leaves.\n"); }close(fd);sem_post(mutex);sem_close(mutex);sem_unlink("mutex");return0;}
Analysis
Only one key ensures mom and dad will not operate on the fridge at the same time (mutual exclusion). That means while mom handles with fridge (in critical region), dad should wait until mom finishes (leaves the critical region).
We regard mom and dad as two processes, then fridge is a shared resource (we use file to implement it) between these two processes and semaphore is the key. The value of semaphore is the number of keys. When a semaphore has only two values, i.e. 0 and 1, it is usually used to achieve mutual exclusion.