# Too Much Milk: Use semaphore

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:

```bash
gcc mom_sol.c -pthread -o mom
gcc dad_sol.c -pthread -o dad
./mom & ./dad &
```

```c
/*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>
int main(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 1
    sem_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 empty
    if (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" already
        if (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 1
    sem_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_unlink
    sem_close(mutex);
    sem_unlink("mutex");
    return 0;
}
```

```c
/*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>
int main(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");
    return 0;
}
```

![](/files/-Lp-5m3cjWvtPcC_xqzH)

## Analysis <a href="#analysis" id="analysis"></a>

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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://eric-lo.gitbook.io/synchronization/too-much-milk-use-semaphore.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
