Программирование >>  Разработка устойчивых систем 

1 ... 183 184 185 [ 186 ] 187 188 189 ... 196


ToastO { assert(O): } Никогда не должен вызываться lendif

void butterO { status = BUTTERED: } void jamO { status = JAMMED: } string getStatusO const { switch(status) {

case DRY: return dry :

case BUTTERED: return buttered :

case JAMMED: return jammed :

default: return error :

int getldO { return id: }

friend ostream& operator (ostream& os, const Toast& t) { return OS Toast t.id : t.getStatus():

typedef CountedPtr< TQueue<Toast> > ToastQueue:

class Toaster : public Runnable {

ToastQueue toastQueue:

int count: public:

Toaster(ToastQueue& tq) : toastQueue(tq). count(O) void runO { try {

whiledThread: :interrupted()) { int delay = rand()/(RAND MAX/5)*100: Thread::sleep(delay): Изготовление тоста Toast t(count++): cout t endl: Постановка в очередь toastQueue->put(t):

} catch(Interrupted Exception&) { /* Exit */ } cout Toaster off endl:

Намазывание масла на тост: class Butterer : public Runnable {

ToastQueue dryQueue. butteredQueue: public:

Butterer(ToastQueue& dry. ToastQueue& buttered) : dryQueue(dry). butteredQueue(buttered) {} void runO { try {

whiledThread: :interrupted()) { Блокировка до появления следующего тоста: Toast t = dryQueue->get(): t. butter О: cout t endl: butteredQueue->put(t):

} catch(Interrupted Exception&) { /* Exit */ } cout Butterer off endl:



Потребление тоста:

class Eater : public Runnable {

ToastQueue finishedQueue:

int counter: public:

Eater(ToastQueue& finished) : finishedQueueCfinished). counter(O) {} void runO { try {

whileCIThread::interrupted()) { Блокировка до появления следующего тоста: Toast t = finishedQueue->get(): Убеждаемся в том, что тосты следуют по порядку и что все они намазаны джемом: ifCt.getldO 1= counter++ t.getStatusO != jammed ) {

cout Error: t endl:

exit(l): } else

cout ChompI t endl:

} catch(Interrupted Exception&) { /* Exit */ } cout Eater off endl:

int mainO {

srand(time(0)): Раскрутка генератора случайных чисел try {

ToastQueue dryQueueCnew TQueue<Toast>),

butteredQueueCnew TQueue<Toast>), finishedQueueCnew TQueue<Toast>):

cout Press <Return> to quit endl:

ThreadedExecutor executor:

executor.execute(new Toaster(dryQueue)):

executor.executeCnew Butterer(dryQueue.butteredQueue)):

executor.executeC

Нанесение джема на тост с маслом: class Jammer : public Runnable {

ToastQueue butteredQueue. finishedQueue: public:

Jammer(ToastQueue& buttered, ToastQueueS finished) : butteredQueue(buttered), finishedQueue(finished) void runO { try {

while(IThread::interrupted()) { Блокировка до появления следующего тоста: Toast t = butteredQueue->get(): t.jamO:

cout t endl: finishedQueue->put(t):

} catch(Interrupted Exception&) { /* Exit */ } cout Jammer off endl:



new Jammer(butteredQueue. finishedQueue)): executor.executeCnew Eater(fi ni shedQueue)); cin.getO:

executor. interruptO: } catch(Synchronization Exception& e) { cerr e.whatO endl:

} III:-

В этом решении немедленно бросаются в глаза два обстоятельства: во-первых, применение контейнера TQueue кардинально сокращает объем и сложность кода в каждом классе Runnable, поскольку все операции по защите и взаимодействию потоков, а также вызовы wait() и signal() теперь выполняются в TQueue. В новой версии классы Runnable не содержат объекты Mutex и Condition. Во-вторых, в программе исчезла связь между классами, потому что каждый класс взаимодействует только со своим контейнером TQueue. Порядок определения классов теперь не имеет значения. Сокращение объема кода и смягчение привязки всегда приветствуются. Из этого можно сделать вывод, что применение контейнера TQueue дает положительный эффект, как и в больщинстве подобных задач.

Функция broadcastO

Функция signalO активизирует один программный поток, находящийся в ожидании объекта Condition. Тем не менее, одного объекта могут дожидаться сразу несколько потоков, и в этом слзае для их активизации лучше воспользоваться функцией broadcastO вместо signal().

В следующей программе объединены многие концепции, с которыми мы познакомились в этой главе. Рассмотрим гипотетическую автоматизированную линию сборки автомобилей. Объект Саг строится в несколько этапов. В примере мы ограничимся одним этапом: когда на готовой раме закрепляются двигатель, трансмиссия и колеса. Объекты Саг передаются из одного места в другое через контейнер CarQueue, который является разновидностью контейнера TQueue. Устройство управления (Director) берет очередной автомобиль (пока в виде голой рамы) из входной очереди CarQueue и помещает его на монтажный стенд (Cradle), где выполняются все операции. В этот момент Director сообщает (при помощи broadcastO) всем ожидающим роботам, что машина находится на месте и готова к монтажу. Три типа роботов начинают работу и отправляют Cradle сообщения о завершении своих задач. Director ожидает, когда все задачи будут завершены, после чего направляет Саг в выходную очередь CarQueue для передачи на следующий этап сборки. Потребителем выходной очереди является объект Reporter, который просто выводит содержимое Саг, чтобы мы могли убедиться в правильном завершении операций.

: Cll:CarBuilder.cpp {RunByHand} Использование функции broadcastO. {L} ZThread linclude <iostream> linclude <string> linclude zthread/Thread.h linclude zthread/Mutex.h linclude zthread/Guard.h linclude zthread/Condition.h



1 ... 183 184 185 [ 186 ] 187 188 189 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика