Читаем 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.

<p>Proper toasting</p>

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.

<p>Broadcast</p>

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( ).

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

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

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

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