The code is very similar to the producer, except that this time we acquire a "used" byte and release a "free" byte, instead of the opposite.
The main() Function
In main(), we create the two threads and call QThread::wait() to ensure that both threads get time to finish before we exit:
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Producer producer;
Consumer consumer;
producer.start();
consumer.start();
producer.wait();
consumer.wait();
return 0;
}
So what happens when we run the program? Initially, the producer thread is the only one that can do anything; the consumer is blocked waiting for the usedBytes semaphore to be released (its initial available() count is 0). Once the producer has put one byte in the buffer, freeBytes.available() is BufferSize - 1 and usedBytes.available() is 1. At that point, two things can happen: Either the consumer thread takes over and reads that byte, or the consumer gets to produce a second byte.
The producer-consumer model presented in this example makes it possible to write highly concurrent multithreaded applications. On a multiprocessor machine, the program is potentially up to twice as fast as the equivalent mutex-based program, since the two threads can be active at the same time on different parts of the buffer.
Be aware though that these benefits aren't always realized. Acquiring and releasing a QSemaphore has a cost. In practice, it would probably be worthwhile to divide the buffer into chunks and to operate on chunks instead of individual bytes. The buffer size is also a parameter that must be selected carefully, based on experimentation.