|
Программирование >> Разработка устойчивых систем
оператор delete для объекта при обнулении счетчика. Вот как выглядит предыдущий пример в случае использования щаблона CountedPtr: : Cll:ReferenceCounting.cpp CountedPtr предотвращает преждевременное уничтожение объекта. {L} ZThread linclude <iostream> linclude zthread/Thread.h li nclude zthread/CountedPtr.h using namespace ZThread: using namespace std: class Count { enum { SZ = 100 }: int n[SZ]: public: void incrementО { for(int i = 0: i < SZ: i++) n[i]++: class Incrementer : public Runnable { CountedPtr<Count> count: public: IncrementerCconst CountedPtr<Count>& с ) : count(c) {} void runO { forCint n = 100: n > 0: n--) { Thread::sleep(250): count->increment(): int mainO { CountedPtr<Count> count(new Count): try { Thread t0(new Incrementer(count)): Thread tKnew Incrementer(count)): } catch(Synchronization Exception& e) { cerr e.whatO endl: } III:- В новой версии класс Incrementer содержит объект CountedPtr, управляющий использованием объекта Count. Внутри функции main() объекты CountedPtr передаются двум объектам Incrementer по значению, поэтому для них вызывается копирующий конструктор с увеличением счетчика ссылок. До тех пор пока задачи продолжают работать, счетчик ссылок остается ненулевым, и объект Count, находящийся под управлением CountedPtr, не уничтожается. Только после заверщения всех задач, использующих Count, объект CountedPtr вызовет (автоматически) оператор delete для объекта Count. Практически во всех случаях, когда объекты используются несколькими задачами, следует поставить эти объекты под контроль шаблона CountedPtr и предотвратить проблемы, связанные с жизненным циклом этих объектов. 550 Глава И Многопоточное программирование Конфликты доступа к ресурсам в следующем примере одна задача генерирует четные числа, а другие задачи эти числа поглощают. Единственная функция потоков-потребителей - проверка действительности (то есть четности) этих чисел. Начнем с определения класса потока-потребителя EvenChecker, поскольку он будет нужен нам во всех последующих примерах. Чтобы отделить EvenChecker от разных типов генераторов, с которыми мы будем экспериментировать, создадим интерфейс Generator с минимально необходимыми функциями, о которых должен знать EvenChecker. Интерфейс содержит функцию nextValue() для получения следующего числа и функцию остановки генератора: : СИ:EvenChecker.h #ifndef EVENCHECKER H #define EVENCHECKER H finclude <iostream> finclude zthread/CountedPtr.h finclude zthread/Thread.h finclude zthread/Cancelable.h finclude zthread/ThreadedExecutor.h class Generator : public ZThread::Cancel able { bool canceled: public: GeneratorO : canceled(false) {} virtual int nextValueO = 0: void cancel О { canceled = true: } bool isCanceledO { return canceled: } class EvenChecker : public ZThread::Runnable { ZThread::CountedPtr<Generator> generator: int id: public: EvenChecker(ZThread::CountedPtr<Generator>& g, int ident) : generator(g), id(ident) {} ~EvenChecker() { std::cout -EvenChecker id std::endl: void runO { whi 1 e(!generator->isCanceledO) { int val = generator->nextValue(): if(val 2 != 0) { std::cout val not even! std::endl: generator->cancelО: Завершение всех задач EvenChecker Тестирование генератора произвольного типа: tempiate<typename GenType> static void test(int n = 10) { std::cout Press Control-C to exit std::endl: try { ZThread::ThreadedExecutor executor: ZThread::CountedPtr<Generator> gp(new GenType): for(int i = 0: i < n; i++) executor.execute(new EvenChecker(gp. i)): } catch(ZThread::Synchronization Exception& e) { #end1f EVENCHECKERJ /:- Класс Generator знакомит читателя с абстрактным классом Cancelable, входящим в библиотеку ZThread. Этот класс предоставляет единый интерфейс для изменения состояния объе1Сга функцией cancel(), а также для проверки ее вызова в прошлом функцией isCanceled(). В нашем примере используется простое решение с логическим флагом - аналогом quitFlag из представленного ранее примера ResponsiveUI.cpp. Обратите внимание: в этом примере класс, реализующий Cancelable, не реализует Runnable. Вместо этого все задачи EvenChecker, зависящие от объекта Cancelable (Generator), проверяют, не были ли они отменены, как показано в run(). Таким образом, задачи, совместно использующие общий ресурс (задачу Generator, реализующую Cancelable), следят за тем, когда ресурс подаст сигнал на завершение. Тем самым устраняется так называемая ситуация гонок, когда две или более задачи независимо реагируют на некоторое условие, что приводит к конфликтам или нарушению логической целостности результатов. Вы должны тщательно продумать механизм защиты от всех возможных сбоев в многопоточной системе. Например, задача не может зависеть от другой задачи, потому что порядок завершения задач не гарантирован. Организуя зависимость задач от объектов (для которых реализован подсчет ссылок с использованием CounterPtr), мы устраняем потенциальную опасность гонок. В следующих разделах мы познакомимся с более общими механизмами управления завершением потоков, поддерживаемыми библиотекой ZThread. Так как Generator может совместно использоваться несколькими объектами EvenChecker, шаблон CountedPtr применяется для подсчета объектов Generator. Последняя функция EvenChecker - статический шаблон функции класса, который готовит и выполняет проверку произвольного типа Generator. Для этого он создает экземпляр генератора в CounterPtr и запускает несколько экземпляров EvenChecker, задействующих этот генератор. Если при использовании Generator происходит сбой, функция test() сообщает об этом и возвращает управление; в противном случае генератор необходимо завершить нажатием клавиш Ctrl+C. Задачи EvenChecker постоянно читают и проверяют значения, полученные от генератора. Обратите внимание: если выражение generator->isCanceled() истинно, функция run() возвращает управление, тем самым сообщая Executor в EvenChecker::test() о завершении задачи. Любая задача EvenChecker может вызвать cancel() для своего генератора, что приведет к корректному завершению всех остальных экземпляров EvenChecker, использующих этот генератор. Класс EvenGenerator устроен очень просто - функция nextValue() выдает следующее четное значение: : СИ:EvenGenerator.срр Межпотоковые коллизии. {L} ZThread linclude <iostream> linclude EvenChecker.h li nclude Zthread/ThreadedExecutor.h using namespace ZThread: using namespace std: class EvenGenerator : public Generator { std::сегг e.whatO std::endl:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |