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

class EvenChecker : public ZThread::Runnable {

  ZThread::CountedPtr generator;

  int id;

public:

  EvenChecker(ZThread::CountedPtr& g, int ident)

  : generator(g), id(ident) {}

  ~EvenChecker() {

    std::cout << "~EvenChecker " << id << std::endl;

  }

  void run() {

    while(!generator->isCanceled()) {

      int val = generator->nextValue();

      if(val % 2 != 0) {

        std::cout << val << " not even!" << std::endl;

        generator->cancel(); // Cancels all EvenCheckers

      }

    }

  }

  // Test any type of generator:

  template static void test(int n = 10) {

    std::cout << "Press Control-C to exit" << std::endl;

    try {

      ZThread::ThreadedExecutor executor;

      ZThread::CountedPtr gp(new GenType);

      for(int i = 0; i < n; i++)

        executor.execute(new EvenChecker(gp, i));

    } catch(ZThread::Synchronization_Exception& e) {

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

    }

  }

};

#endif // EVENCHECKER_H ///:~


The Generator class introduces the pure abstract Cancelable class, which is part of the ZThread library. The goal of Cancelable is to provide a consistent interface to change the state of an object via the cancel( ) function and to see whether the object has been canceled with the isCanceled( ) function. Here, the simple approach of a bool canceled flag is used, similar to the quitFlag previously seen in ResponsiveUI.cpp. Note that in this example the class that is Cancelable is not Runnable. Instead, all the EvenChecker tasks that depend on the Cancelable object (the Generator) test it to see if it’s been canceled, as you can see in run( ). This way, the tasks that share the common resource (the Cancelable Generator) watch that resource for the signal to terminate. This eliminates the so-called race condition, in which two or more tasks race to respond to a condition and thus collide or otherwise produce inconsistent results. You must be careful to think about and protect against all the possible ways a concurrent system can fail. For example, a task cannot depend on another task, because there’s no guarantee of the order in which tasks will be shut down. Here, by making tasks depend on non-task objects, we eliminate the potential race condition.

In later sections, you’ll see that the ZThread library contains more general mechanisms for termination of threads.

Since multiple EvenChecker objects may end up sharing a Generator, the CountedPtr template is used to reference count the Generator objects.

The last member function in EvenChecker is a static member template that sets up and performs a test of any type of Generator by creating one inside a CountedPtr and then starting a number of EvenCheckers that use that Generator. If the Generator causes a failure, test( ) will report it and return; otherwise, you must press Control-C to terminate it.

EvenChecker tasks constantly read and test the values from their associated Generator. Note that if generator->isCanceled( ) is true, run( ) returns, which tells the Executor in EvenChecker::test( ) that the task is complete. Any EvenChecker task can call cancel( ) on its associated Generator, which will cause all other EvenCheckers using that Generator to gracefully shut down.

The EvenGenerator is simple –nextValue( ) produces the next even value:

//: C11:EvenGenerator.cpp

// When threads collide.

//{L} ZThread

#include "EvenChecker.h"

#include "zthread/ThreadedExecutor.h"

#include

using namespace ZThread;

using namespace std;


class EvenGenerator : public Generator {

  int currentEvenValue;

public:

  EvenGenerator() { currentEvenValue = 0; }

  ~EvenGenerator() { cout << "~EvenGenerator" << endl; }

  int nextValue() {

    currentEvenValue++; // Danger point here!

    currentEvenValue++;

    return currentEvenValue;

  }

};


int main() {

  EvenChecker::test();

} ///:~


It’s possible for one thread to call nextValue( ) after the first increment of currentEvenValue and before the second (at the place in the code commented "Danger point here!"), in which case the value would be in an "incorrect" state. To prove that this can happen, EvenChecker::test( ) creates a group of EvenChecker objects to continually read the output of an EvenGenerator and test to see if each one is even. If not, the error is reported and the program is shut down.

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

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

3ds Max 2008
3ds Max 2008

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

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

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