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

  void run() {

    try {

      while(!Thread::interrupted()) {

        {

          Guard g(lock);

          while(!gotToast)

            toastReady.wait();

          buttered++;

        }

        cout << "Buttering toast " << buttered << endl;

        jammer->moreButteredToastReady();

        {

          Guard g(lock);

          gotToast = false;

        }

      }

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

    cout << "Butterer off" << endl;

  }

};


class Toaster : public Runnable {

  CountedPtr butterer;

  int toasted;

public:

  Toaster(CountedPtr& b) : butterer(b) {

    toasted = 0;

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

  }

  void run() {

    try {

      while(!Thread::interrupted()) {

        Thread::sleep(rand()/(RAND_MAX/5)*100);

        // ...

        // Create new toast

        // ...

        cout << "New toast " << ++toasted << endl;

        butterer->moreToastReady();

      }

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

    cout << "Toaster off" << endl;

  }

};


int main() {

  try {

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

    CountedPtr jammer(new Jammer);

    CountedPtr butterer(new Butterer(jammer));

    ThreadedExecutor executor;

    executor.execute(new Toaster(butterer));

    executor.execute(butterer);

    executor.execute(jammer);

    cin.get();

    executor.interrupt();

  } catch(Synchronization_Exception& e) {

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

  }

} ///:~


The classes are defined in the reverse order that they operate to simplify forward-referencing issues.

Jammer and Butterer both contain a Mutex, a Condition, and some kind of internal state information that changes to indicate that the process should suspend or resume. (Toaster doesn’t need these since it is the producer and doesn’t have to wait on anything.) The two run( ) functions perform an operation, set a state flag, and then call wait( ) to suspend the task. The moreToastReady( ) and moreButteredToastReady( ) functions change their respective state flags to indicate that something has changed and the process should consider resuming and then call signal( ) to wake up the thread.

The difference between this example and the previous one is that, at least conceptually, something is being produced here: toast. The rate of toast production is randomized a bit, to add some uncertainty. And you’ll see that when you run the program, things aren’t going right, because many pieces of toast appear to be getting dropped on the floor—not buttered, not jammed.

Solving threading problems with queues

Often, threading problems are based on the need for tasks to be serialized—that is, to take care of things in order. ToastOMatic.cpp must not only take care of things in order, it must be able to work on one piece of toast without worrying that toast is falling on the floor in the meantime. You can solve many threading problems by using a queue that synchronizes access to the elements within:

//: C11:TQueue.h

#ifndef TQUEUE_H

#define TQUEUE_H

#include "zthread/Thread.h"

#include "zthread/Condition.h"

#include "zthread/Mutex.h"

#include "zthread/Guard.h"

#include


template class TQueue {

  ZThread::Mutex lock;

  ZThread::Condition cond;

  std::deque data;

public:

  TQueue() : cond(lock) {}

  void put(T item) {

    ZThread::Guard g(lock);

    data.push_back(item);

    cond.signal();

  }

  T get() {

    ZThread::Guard g(lock);

    while(data.empty())

      cond.wait();

    T returnVal = data.front();

    data.pop_front();

    return returnVal;

  }

};

#endif // TQUEUE_H ///:~


This builds on the Standard C++ Library deque by adding:

1.Synchronization to ensure that no two threads add objects at the same time.

2.wait( ) and signal( ) so that a consumer thread will automatically suspend if the queue is empty, and resume when more elements become available.

This relatively small amount of code can solve a remarkable number of problems.

Here’s a simple test that serializes the execution of LiftOff objects. The consumer is LiftOffRunner, which pulls each LiftOff object off the TQueue and runs it directly. (That is, it uses its own thread by calling run( ) explicitly rather than starting up a new thread for each task.)

//: C11:TestTQueue.cpp

//{L} ZThread

#include

#include

#include "TQueue.h"

#include "zthread/Thread.h"

#include "LiftOff.h"

using namespace ZThread;

using namespace std;


class LiftOffRunner : public Runnable {

  TQueue rockets;

public:

  void add(LiftOff* lo) { rockets.put(lo); }

  void run() {

    try {

      while(!Thread::interrupted()) {

        LiftOff* rocket = rockets.get();

        rocket->run();

      }

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

    cout << "Exiting LiftOffRunner" << endl;

  }

};


int main() {

  try {

    LiftOffRunner* lor = new LiftOffRunner;

    Thread t(lor);

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

      lor->add(new LiftOff(10, i));

    cin.get();

    lor->add(new LiftOff(10, 99));

    cin.get();

    t.interrupt();

  } catch(Synchronization_Exception& e) {

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

  }

} ///:~


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

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

3ds Max 2008
3ds Max 2008

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

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

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