|
Программирование >> Разработка устойчивых систем
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
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |