bool waitingForCancel;

public:

  Entrance(CountedPtr& cnt,

    CountedPtr& disp, int idn)

  : count(cnt), display(disp), id(idn), number(0),

    waitingForCancel(false) {}

  void run() {

    while(!count->isPaused()) {

      number++;

      {

        ostringstream os;

        os << *this << " Total: "

           << count->increment() << endl;

        display->output(os);

      }

      Thread::sleep(100);

    }

    waitingForCancel = true;

    while(!count->isCanceled()) // Hold here...

      Thread::sleep(100);

    ostringstream os;

    os << "Terminating " << *this << endl;

    display->output(os);

  }

  int getValue() {

    while(count->isPaused() && !waitingForCancel)

      Thread::sleep(100);

    return number;

  }

  friend ostream&

  operator<<(ostream& os, const Entrance& e) {

    return os << "Entrance " << e.id << ": " << e.number;

  }

};

int main() {

  cout << "Press to quit" << endl;

  CountedPtr count(new Count);

  vector v;

  CountedPtr display(new Display);

  const int sz = 5;

  try {

    ThreadedExecutor executor;

    for(int i = 0; i < sz; i++) {

      Entrance* task = new Entrance(count, display, i);

      executor.execute(task);

      // Save the pointer to the task:

      v.push_back(task);

    }

    cin.get(); // Wait for user to press

    count->pause(); // Causes tasks to stop counting

    int sum = 0;

    vector::iterator it = v.begin();

    while(it != v.end()) {

      sum += (*it)->getValue();

      it++;

    }

    ostringstream os;

    os << "Total: " << count->value() << endl

       << "Sum of Entrances: " << sum << endl;

    display->output(os);

    count->cancel(); // Causes threads to quit

  } catch(Synchronization_Exception& e) {

    cerr << e.what() << endl;

  }

} ///:~

Count is the class that keeps the master count of garden visitors. The single Count object defined in main( ) as count is held as a CountedPtr in Entrance and thus is shared by all Entrance objects. A FastMutex called lock is used in this example instead of an ordinary Mutex because a FastMutex uses the native operating system mutex and will thus yield more interesting results.

A Guard is used with lock in increment( ) to synchronize access to count. This function uses rand( ) to cause a yield( ) roughly half the time, in between fetching count into temp and incrementing and storing temp back into count. Because of this, if you comment out the Guard object definition, you will rapidly see the program break because multiple threads will be accessing and modifying count simultaneously.

The Entrance class also keeps a local number with the number of visitors that have passed through this particular entrance. This provides a double-check against the count object to make sure that the proper number of visitors is being recorded. Entrance::run( ) simply increments number and the count object and sleeps for 100 milliseconds.

In main, a vector is loaded with each Entrance that is created. After the user presses , this vector is used to iterate over all the individual Entrance values and total them.

This program goes to quite a bit of extra trouble to shut everything down in a stable fashion. Part of the reason for this is to show just how careful you must be when terminating a multithreaded program, and part of the reason is to demonstrate the value of interrupt( ), which you will learn about shortly.

Перейти на страницу:

Похожие книги