Читаем Thinking In C++. Volume 2: Practical Programming полностью

The tasks are placed on the TQueue by main( ) and are taken off the TQueue by the LiftOffRunner. Notice that LiftOffRunner can ignore the synchronization issues because they are solved by the TQueue.

Proper toasting

To solve the ToastOMatic.cpp problem, we can run the toast through TQueues between processes. And to do this, we will need actual toast objects, which maintain and display their state:

//: C11:ToastOMaticMarkII.cpp

// Solving the problems using TQueues

//{L} ZThread

#include "zthread/Thread.h"

#include "zthread/Mutex.h"

#include "zthread/Guard.h"

#include "zthread/Condition.h"

#include "zthread/ThreadedExecutor.h"

#include "TQueue.h"

#include

#include

#include

#include

using namespace ZThread;

using namespace std;


class Toast {

  enum Status { dry, buttered, jammed };

  Status status;

  int id;

public:

  Toast(int idn) : id(idn), status(dry) {}

  void butter() { status = buttered; }

  void jam() { status = jammed; }

  string getStatus() const {

    switch(status) {

      case dry: return "dry";

      case buttered: return "buttered";

      case jammed: return "jammed";

      default: return "error";

    }

  }

  int getId() { return id; }

  friend ostream& operator<<(ostream& os, const Toast& t) {

    return os << "Toast " << t.id << ": " << t.getStatus();

  }

};


typedef CountedPtr< TQueue > ToastQueue;


class Toaster : public Runnable {

  ToastQueue toastQueue;

  int count;

public:

  Toaster(ToastQueue& tq) : toastQueue(tq), count(0) {

    srand(time(0)); // Seed the random number generator

  }

  void run() {

    try {

      while(!Thread::interrupted()) {

        int delay = rand()/(RAND_MAX/5)*100;

        Thread::sleep(delay);

        // Make toast

        Toast t(count++);

        cout << t << endl;

        // Insert into queue

        toastQueue->put(t);

      }

    } catch(Interrupted_Exception&) { /* Exit */ }

    cout << "Toaster off" << endl;

  }

};


// Apply butter to toast:

class Butterer : public Runnable {

  ToastQueue dryQueue, butteredQueue;

public:

  Butterer(ToastQueue& dry, ToastQueue& buttered)

  : dryQueue(dry), butteredQueue(buttered) {}

  void run() {

    try {

      while(!Thread::interrupted()) {

        // Blocks until next piece of toast is available:

        Toast t = dryQueue->get();

        t.butter();

        cout << t << endl;

        butteredQueue->put(t);

      }

    } catch(Interrupted_Exception&) { /* Exit */ }

    cout << "Butterer off" << endl;

  }

};


// Apply jam to buttered toast:

class Jammer : public Runnable {

  ToastQueue butteredQueue, finishedQueue;

public:

  Jammer(ToastQueue& buttered, ToastQueue& finished)

  : butteredQueue(buttered), finishedQueue(finished) {}

  void run() {

    try {

      while(!Thread::interrupted()) {

        // Blocks until next piece of toast is available:

        Toast t = butteredQueue->get();

        t.jam();

        cout << t << endl;

        finishedQueue->put(t);

      }

    } catch(Interrupted_Exception&) { /* Exit */ }

    cout << "Jammer off" << endl;

  }

};


// Consume the toast:

class Eater : public Runnable {

  ToastQueue finishedQueue;

  int counter;

public:

  Eater(ToastQueue& finished)

  : finishedQueue(finished), counter(0) {}

  void run() {

    try {

      while(!Thread::interrupted()) {

        // Blocks until next piece of toast is available:

        Toast t = finishedQueue->get();

        // Verify that the toast is coming in order,

        // and that all pieces are getting jammed:

        if(t.getId() != counter++ ||

           t.getStatus() != "jammed") {

          cout << ">>>> Error: " << t << endl;

          exit(1);

        } else

          cout << "Chomp! " << t << endl;

      }

    } catch(Interrupted_Exception&) { /* Exit */ }

    cout << "Eater off" << endl;

  }

};


int main() {

  try {

    ToastQueue dryQueue(new TQueue),

butteredQueue(new TQueue),

finishedQueue(new TQueue);

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

    ThreadedExecutor executor;

    executor.execute(new Toaster(dryQueue));

    executor.execute(new Butterer(dryQueue,butteredQueue));

    executor.execute(

      new Jammer(butteredQueue, finishedQueue));

    executor.execute(new Eater(finishedQueue));

    cin.get();

    executor.interrupt();

  } catch(Synchronization_Exception& e) {

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

  }

} ///:~


Two things are immediately apparent in this solution: first, the amount and complexity of code within each Runnable class is dramatically reduced by the use of the TQueue, because the guarding, communication, and wait( )/signal( ) operations are now taken care of by the TQueue. The Runnable classes don’t have Mutexes or Condition objects anymore. Second, the coupling between the classes is eliminated because each class communicates only with its TQueues. Notice that the definition order of the classes is now independent. Less code and less coupling is always a good thing, which suggests that the use of the TQueue has a positive effect here, as it does on most problems.

Broadcast

The signal( ) function wakes up a single thread that is waiting on a Condition object. However, multiple threads may be waiting on the same condition object, and in that case you’ll want to wake them all up using broadcast( ) instead of signal( ).

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

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

3ds Max 2008
3ds Max 2008

Одни уверены, что нет лучшего способа обучения 3ds Мах, чем прочитать хорошую книгу. Другие склоняются к тому, что эффективнее учиться у преподавателя, который показывает, что и как нужно делать. Данное издание объединяет оба подхода. Его цель – сделать освоение 3ds Мах 2008 максимально быстрым и результативным. Часто после изучения книги у читателя возникают вопросы, почему не получился тот или иной пример. Видеокурс – это гарантия, что такие вопросы не возникнут: ведь автор не только рассказывает, но и показывает, как нужно работать в 3ds Мах.В отличие от большинства интерактивных курсов, где работа в 3ds Мах иллюстрируется на кубиках-шариках, данный видеокурс полностью практический. Все приемы работы с инструментами 3ds Мах 2008 показаны на конкретных примерах, благодаря чему после просмотра курса читатель сможет самостоятельно выполнять даже сложные проекты.

Владимир Антонович Верстак , Владимир Верстак

Программирование, программы, базы данных / Программное обеспечение / Книги по IT