An example from The Linux Programming Interface:
In the producer threads, we would have code such as the following:
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static int avail = 0;
/* Code to produce a unit omitted */
s = pthread_mutex_lock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_lock");
avail++; /* Let consumer know another unit is available */
s = pthread_mutex_unlock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_unlock");
And in the main (consumer) thread, we could employ the following code:
for (;;) {
s = pthread_mutex_lock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_lock");
while (avail > 0) {
/* Consume all available units */
/* Do something with produced unit */
avail--;
}
s = pthread_mutex_unlock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_unlock");
}
The above code works, but it wastes CPU time, because the main thread continually loops, checking the state of the variable
avail
. A condition variable remedies this problem. It allows a thread to sleep (wait) until another thread notifies (signals) it that it must do something.
The book then gives what he thinks is a better version, with condition variable:
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static int avail = 0;
Producer thread:
/* Code to produce a unit omitted */
s = pthread_mutex_lock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_lock");
avail++; /* Let consumer know another unit is available */
s = pthread_mutex_unlock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_unlock");
s = pthread_cond_signal(&cond); /* Wake sleeping consumer */
if (s != 0)
errExitEN(s, "pthread_cond_signal");
Consumer thread:
for (;;) {
s = pthread_mutex_lock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_lock");
while (avail == 0) { /* Wait for something to consume */
s = pthread_cond_wait(&cond, &mtx);
if (s != 0)
errExitEN(s, "pthread_cond_wait");
}
while (avail > 0) { /* Consume all available units */
/* Do something with produced unit */
avail--;
}
s = pthread_mutex_unlock(&mtx);
if (s != 0)
errExitEN(s, "pthread_mutex_unlock");
/* Perhaps do other work here that doesn't require mutex lock */
}
Question: Why the first version is less effcient(wastes CPU time) compared to the second one? I can't see the difference.
Btw, could you give me an example which may illustrate the author's point of view, which I think is:
You can use mutex along with condition variable to improve perfomance, compared to the one that uses only mutex.
avail
, unblocks the mutex -> consumer continues. – Swashbuckler