Thread Rendezvous
- semaphore::wait() and semaphore::signal() can be exploited to provide a different form of thread communication: rendezvous.
- Here's our first example (full program is right here):
static const unsigned int kNumBuffers = 30;
static const unsigned int kNumCycles = 4;
static char buffer[kNumBuffers];
static semaphore emptyBuffers(kNumBuffers);
static semaphore fullBuffers(0);
static void writer() {
cout << oslock << "Writer: ready to write." << endl << osunlock;
for (unsigned int i = 0; i < kNumCycles * kNumBuffers; i++) {
char ch = prepareData();
emptyBuffers.wait(); // don't try to write to a slot unless you know it's empty
buffer[i % kNumBuffers] = ch;
fullBuffers.signal(); // signal reader there's more stuff to read
cout << oslock << "Writer: published data packet with character '"
<< ch << "'." << endl << osunlock;
}
}
static void reader() {
cout << oslock << "\t\tReader: ready to read." << endl << osunlock;
for (unsigned int i = 0; i < kNumCycles * kNumBuffers; i++) {
fullBuffers.wait(); // don't try to read from a slot unless you know it's full
char ch = buffer[i % kNumBuffers];
emptyBuffers.signal(); // signal writer there's a slot that can receive data
processData(ch);
cout << oslock << "\t\tReader: consumed data packet "
<< "with character '" << ch << "'." << endl << osunlock;
}
}
int main(int argc, const char *argv[]) {
thread w(writer);
thread r(reader);
w.join();
r.join();
return 0;
}
- Think of the writer thread as one that serves data to a network connection, and think of the reader thread as one that consumes it.
- Two semaphores are used to synchronize the two so that:
- reader is never further along than writer, and
- writer is never so far ahead of reader that it clobbers data that has yet to be consumed.