Please work out the pre-lab problems before your next lab section. The GSI/IAs will go over these problems during the lab section.

Implement your solutions using the semaphores that are provided by the Project 1 thread library.

[pre-lab] 1. Synchronization with semaphores

Redo the luxury box problem from the previous discussion using semaphores. To ensure some fairness and prevent starvation, your solution shall use the following policy. If PAC 12 (BIG 10) fans are in the luxury box, then newly arriving PAC 12 (BIG 10) fans can keep going in as long as BIG 10 (PAC 12) fans are not waiting; else new arrivals must wait. When all PAC 12 (BIG 10) fans leave the luxury box, all waiting BIG 10 (PAC 12) fans are admitted. Write the following procedures:

[pre-lab] 2. Barrier Synchronization

Some applications are divided into phases and have a rule that no process may proceed into the next phase until all processes are ready to proceed to the next phase.

A running race is to take place. There are N runners and one official starter of the race. The starter waits until all of the runners arrive at the starting line. Once all the runners have arrived, the starter releases all the runners to start the race. Write the following procedures using semaphores to simulate this situation:

[in-lab] 3. Opaque pointers (pImpl)

In Project 2, the classes we provide (cpu, cv, mutex, thread) include "opaque pointers", i.e., pointers to a class that you define. This allows you to add custom functions and data members to these classes without changing the provided header files or recompiling libcpu.o. In this question, you'll gain experience with this design pattern (see this writeup for more details).

Here is the header file (HelloWorld.h) for a class HelloWorld. You may not change this file.


 *  This code is all the user of the library has to include.
class HelloWorld {


    void speak();

    class HelloWorldImpl;
    HelloWorldImpl *pImpl;
#endif // _HELLOWORLD_H

The HelloWorld class includes an opaque pointer to a class HelloWorldImpl, which you can define. Complete the following header file (HelloWorldImpl.h) for the HelloWorldImpl class.


#include "HelloWorld.h"

class HelloWorld::HelloWorldImpl {
    // add a function hello()
    // add a data member to count the number of times hello() has been called

Next, complete the following code for HelloWorldImpl.cpp:

#include <iostream>
#include "HelloWorld.h"
#include "HelloWorldImpl.h"

void HelloWorld::HelloWorldImpl::hello() {
    // increment the count of how many times hello() has been called on this instance
    // print hello world and the current count

And complete the following code for HelloWorld.cpp:

#include "HelloWorld.h"
#include "HelloWorldImpl.h"

HelloWorld::HelloWorld() {
    // allocate an instance of HelloWorldImpl and remember its address in pImpl

HelloWorld::~HelloWorld() {
    // delete the instance of HelloWorldImpl that you allocated above

void HelloWorld::speak() {
    // call your impl's hello() function 

Here's the source code for a program main.cpp, which uses the HelloWorld (but need not know anything about the HelloWorldImpl class):

#include "HelloWorld.h"

void main() {
    HelloWorld greeter;
    for (int i = 0; i < 3; ++i) {

Compile it all together with:

g++ -c HelloWorld.cpp					# creates HelloWorld.o
g++ -c HelloWorldImpl.cpp				# creates HelloWorldImpl.o
g++ -o main main.cpp HelloWorld.o HelloWorldImpl.o

Note how you can add members to HelloWorldImpl without modifying or recompiling HelloWorld.cpp or HelloWorld.h.