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

1 ... 179 180 181 [ 182 ] 183 184 185 ... 196


Учтите, что вызов t.interrupt() может произойти раньше вызова blocked.f() (хотя это и м;1.1о ср()Я1 по).

void fO { Guard<Mutex> g(lock): Никогда не будет доступен

class Blocked2 : public Runnable {

BlockedMutex blocked: public:

void runO { try {

cout Waiting for f() in BlockedMutex endl; blocked.fO: } catch(Interrupted Exception& e) { cerr e.whatO endl; Завершение задачи

int mainCint argc. char* argv[]) { try {

Thread tCnew Blocked2): t.interruptC): } catchCSynchronization Exception& e) { cerr e.whatO endl:

} III:-

Класс BlockedMutex содержит конструктор, который захватывает мутекс объекта и не освобождает его. Из-за этого попытка вызова f() всегда блокируется, поскольку захватить мутекс никогда не удастся. В Blocked2 функция run() будет остановлена при вызове blocked.f(). Если запустить программу, вы увидите, что, в отличие от предыдущего примера, interrupt() позволяет прервать вызов, заблокированный по ожиданию мутекса.

Проверка прерывания

при вызове interrupt() для программного потока прерывание происходит либо если задача входит в блокирующую операцию, либо если она уже заблокирована (как отмечалось ранее, исключение составляют операции ввода-вывода, которые не прерываются).

Но что, если написанный вами код может включать пли не включать блокировку в зависимости от условий своего выполнения? Если бы выход всегда производился только по запуску исключения в блокирующем вызове, в некоторых случаях выход из цикла run() стал бы невозможным. Следовательно, если задача завершается вызовом interrupt(), необходимо предусмотреть вторую возможность выхода на тот случай, если в цикле run() не будет сделано ни одного блокирующего вы.зова.

Такую возможность предоставляет статус прерывания, устанавливаемый вызовом interrupt(). Для проверки статуса прерывания используется функция interrupted(). Она не только сообщает, вызывалась ли ранее функция interrupt(), но и сбрасывает статус прерывания. Сброс статуса прерывания гарантирует, что библиотека не



lU 1 11.

NeedsCleanupCint ident) : id(ident) { cout NeedsCleanup id endl:

~NeedsCTeanup() { cout -NeedsCleanup id endl:

class Blocked3 : public Runnable {

volatile double d: public:

Blocked3() : d(O.O) {}

void runO { try {

while(IThread::interrupted()) { pointl:

NeedsCleanup nl(l): cout Sleeping endl: Thread::sieep(1000): point2:

NeedsCleanup n2(2): cout Calculating endl: Продолжительная неблокирующая операция: forCint i = 1: i < 100000: i++) d = d + CPI + E) / Cdouble)i:

cout Exiting via whileC) test endl: } catchCInterrupted Exception&) { cout Exiting via Interrupted Exception endl

int mainCint argc. char* argv[]) { ifCargc != 2) { cerr usage: argv[0]

оповестит о прерывании задачи дважды. Вы будете оповещены либо одним вызовом Interrupted Exception, либо одной успешной проверкой Thread::interrupted(). Если вам потребуется снова проверить, была ли прервана задача, сохраните результат, полученный при вызове Thread::interrupted().

В следующем примере показан типичный способ обработки обоих вариантов (с блокировкой и без) выхода из цикла в функции гип() при установленном статусе прерывания:

: СИ:Interrupt1ng3.cpp {RunByHand)

Основная идиома прерывания задач.

{L} ZThread

#1 nclude <1ostream>

#1nclude zthread/Thread.h

using namespace ZThread:

using namespace std:

const double PI = 3.14159265358979323846: const double E = 2.7182818284590452354:

class NeedsCleanup {

int id: public:



int delay = atoi(argv[l]): try {

Thread t(new BlockedS): Thread::sleep(delay): t.interruptO: } catch(Synchromz3tion Exception& e) ( cerr e.whatO endl:

} III:-

Класс NeedsCleanup подчеркивает необходимость освобождения ресурсов при выходе из цикла через исключение. Обратите внимание на то, что в Blocked3::run() не определяются указатели, потому что по соображениям безопасности исключений все ресурсы должны инкапсулироваться в стековых объектах, чтобы обработчик исключений мог автоматически освободить их вызовом деструктора.

В командной строке программе передается аргумент, определяющий время задержки в миллисекундах перед вызовом interrupt(). Используя разные задержки, можно выйти из Blocked3::run() в разных точках цикла: в блокирующем вызове sleepO и в неблокирующих математических вычислениях. Вы увидите, что при вызове interruptO после метки point2 (во время неблокирующей операции) сначала заверщается цикл, затем уничтожаются локальные o6iieKTbi и, наконец, происходит выход из цикла по условию while. Но если interrupt() вызывается между pointl и point2 (после команды while, но перед или во время блокирующей операции sleepO), выход из задачи происходит через Interrupted Exception. В этом случае уничтожаются только те стековые объекты, которые были созданы до точки запуска исюшчения, и вам предоставляется возможность выполнить всю прочую зачистку в секции catch.

Класс, спроектированный для обработки interrupt(), должен обеспечить сохранение целостности своего состояния. Обычно это означает, что все захваты ресурсов должны инкапсулироваться в стековых объектах, чтобы деструкторы вызывались независимо от способа выхода из run(). При правильной реализации код выглядит достаточно элегантно. Вы можете создавать компоненты, которые полностью инкапсулируют свои механизмы синхронизации, но при этом реагируют на внешнее воздействие (через interrupt()) без включения специальных функций в интерфейс объекта.

Кооперация между программными потоками

Как было показано ранее, при параллельном запуске нескольких задач в разных программных потоках можно предотвратить нежелательный доступ задач к чужим ресурсам, для чего работа задач синхронизируется при помощи мутексов. Другими словами, если две задачи оспаривают друг у друга общий ресурс (обычно память), можно воспользоваться мутексом, чтобы в любой момент времени ресурс был доступен лишь для одной задачи.

Разобравшись с этим вопросом, можно переходить к вопросу кооперации потоков, то есть их совместной работе над некоторой проблемой. Поскольку проблема изменяется, нужно сделать так, чтобы потоки не просто не мешали друг другу.

clelay-1n-m11liseconds endl: exit(l):



1 ... 179 180 181 [ 182 ] 183 184 185 ... 196

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