|
Программирование >> Разработка устойчивых систем
using namespace std; int mainO { try { Thread t(new LiftOff(lO)); cout Waiting for Liftoff endl; } catch(Synchronization Exception& e) { cerr e.whatO endl; } III:- Класс Synchronization Exception входит в библиотеку ZThreads и является базовым классом для всех исключений ZThreads. Это исключение запускается при возникновении ошибок запуска или использования потока. Конструктору Thread передается только указатель на объект Runnable. При создании объекта Thread выполняется вся необходимая инициализация программного потока, после чего вызывается функция run() класса Runnable для запуска задачи. Хотя фактически конструктор Thread запускает долго выполняемую функцию, он быстро возврашает управление. Таким образом, вызванная в нашем примере функция LiftOff::run() продолжает работать, но поскольку она выполняется в другом программном потоке, программный поток main() продолжает выполнять другие операции (причем эта возможность не ограничивается потоком main() - из любого программного потока можно запустить другой программный поток). В этом нетрудно убедиться, запустив программу. Хотя main() передает управление функции Liftoff::run(), сообщение Waiting for LiftOff появляется до завершения обратного отсчета. Получается, что программа выполняет две функции сразу - LiftOff::run() и main(). В программу можно легко добавить новые программные потоки для решения новых подзадач. В следующем примере обратный отсчет ведется сразу в нескольких потоках: ; Cll:MoreBasicThreads.cpp Добавление новых программных потоков {L} ZThread linclude <iostream> linclude LiftOff.h linclude zthread/Thread.h using namespace ZThread; using namespace std; int mainO { const int sz = 5; try { forCint i = 0; i < sz; i++) Thread tCnew LiftOff(10. i)); cout Waiting for Liftoff endl; } catch(Synchronization Exception& e) { cerr e.whatO endl; } III:- Второй аргумент конструктора LiftOff предназначен для идентификации задач. Запустив программу, вы увидите, что система параллельно выполняет сразу несколько задач, последовательно передавая управление разным программным потокам. Переключение автоматически осуществляется планировщиком программ- ных потоков. В многопроцессорных системах планировщик потоков распределяет потоки между процессорами. Цикл for поначалу выглядит немного странно - переменная t создается локально в цикле, а затем немедленно выходит из области видимости и уничтожается. Создается впечатление, что программный поток тоже немедленно уничтожается, но выходные данные программы показывают, что на самом деле потоки продолжают работать. При создании объекта Thread программный поток регистрируется в системе, что обеспечивает продолжение его существования. Хотя стековый объект Thread теряется, сам поток продолжает жить вплоть до завершения задачи. С позиций С++ такое поведение выглядит противоестественно, но концепция программных потоков отходит от нормы: запуск потока создает отдельную производственную линию, которая продолжает работать после выхода из функции. Ускорение реакции пользовательского интерфейса Как уже отмечалось, многопоточная модель часто применяется для повышения скорости реакции пользовательского интерфейса. Графические интерфейсы в этой книге не рассматриваются, и ниже приводится простой пример с консольным интерфейсом. Следующая программа читает строки из файла и выводит их на консоль, делая секундную паузу после вывода каждой строки (механизм организации задержки рассматривается далее в этой главе). Во время паузы программа не реагирует на ввод пользователя, ее интерфейс блокируется: : Cll:UnresponsiveUI.cpp Блокировка пользовательского интерфейса в однопоточном приложении. {L} ZThread #1ncTude <iostream> #1nclude <fstream> #1 nclude <strlng> #1 nclude zthread/Thread.h using namespace std: using namespace ZThread: int mainO { cout Press <Enter> to quit: endl: i fstream fi1e( UnresponsiveUI.cpp ): string line: while(getline(file. line)) { cout line endl: Thread::sleep(1000): Время в миллисекундах Чтение ввода с консоли cin.getO: cout Shutting down... endl: } /:- Чтобы программа перестала блокироваться, задачу вывода файла можно выполнять в отдельном программном потоке. В этом сл)ае главный поток отслеживает действия пользователя и реагирует на них: : ClLResponsiveUI.cpp Многопоточная модель для ускорения реакции пользовательского интерфейса. {L} ZThread linclude <iostream> linclude <fstreani> linclude <string> linclude zthread/Thread.h using namespace ZThread: using namespace std: class DisplayTask : public Runnable { ifstream in: string line: bool quitFlag: public: DisplayTask(const strings file) : quitFlag(false) { in.open(file.c str()): -DisplayTaskO { in.closeO: } void runO { while(getline(in, line) && IquitFlag) { cout 1i ne endl: Thread::sieep(1000): void quitO { quitFlag = true: } int mainO { try { cout Press <Enter> to quit: endl: DisplayTask* dt = new DisplayTask( ResponsiveUI.cpp ): Thread t(dt): cin.getO: dt->quit(): } catch(Synchronization Exception& e) { cerr e.whatO endl: cout Shutting down... endl: } III:- Теперь главный программный поток main() немедленно реагирует на нажатие клавиши Enter и вызывает функцию quit() для DisplayTask. Данный пример также демонстрирует организацию взаимодействия между задачами - задача в программном потоке main() должна приказать задаче DisplayTask завершиться. Поскольку у нас имеется указатель на DisplayTask, кажется, что для завершения задачи достаточно вызвать оператор delete для этого указателя, однако такая программа будет работать ненадежно. Дело в том, что при уничтожении задача может выполнять какую-нибудь важную операцию, и ее прерывание приведет к нестабильному состоянию. В нашем примере задача сама решает, в какой момент она может безопасно завершиться. Чтобы оповестить задачу о необходимости завершиться, проше всего установить логический флаг. Достигнув точки стабильности, задача проверяет флаг и выполняет всю необходимую зачистку перед возвратом управления из гип(). Выход из гип() сообщает классу Thread о завершении задачи. Наша программа достаточно проста, и никаких проблем с ней быть не должно. Тем не менее, в ней присутствуют мелкие недостатки, связанные с межпроцессными взаимодействиями. Эта важная тема будет рассматриваться далее в этой главе.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки. |