Locks (also known as mutexes, short for mutual exclusion locks) provide mutual exclusion to shared data inside a critical session. They are implemented by means of two atomic routines:
acquire, which waits for a lock, and takes it when possible; and release, which unlocks the lock and wakes up the waiting threads. The rules for using locks/mutexes are the following:
1. only one person can have the lock;
2. locks must be acquired before accessing shared data;
3. locks must release after the critical section is done;
4. locks are initially released.
The syntax for using locks in C/C++ is the following:
pthread_mutex_init(&l);
...
pthread_mutex_lock(&l);
update data // this is the critical section
pthread_mutex_unlock(&l);
Let us now try to rewrite the "Too Much Milk" problem in a simpler, cleaner, more symmetric, and portable way, using locks. In order to do so, the code for Thread A (and also for Thread B) would be the following:
pthread_mutex_lock(&l)
if (no milk)
buy milk
pthread_mutex_unlock(&l)