Поток при выполнении может запрашивать дополнительные ресурсы, например, файлы или мьютексы, но они становятся доступными для всех потоков процесса. Существуют ограничения на ресурсы, которые может использовать один процесс. Таким образом, все потоки в общей сложности не должны превышать предельный объем ресурсов, выделяемых процессу. Если поток попытается расходовать больше ресурсов, чем предусмотрено предельным объемом, формируется сигнал о том, что достигнут предельный объем ресурсов для данного процесса. Потоки, которые используют ресурсы, должны следить за тем, чтобы эти ресурсы не оставались в нестабильном состоянии после их аннулирования. Поток, который открыл файл или создал мьютекс, может завершиться, оставив этот файл открытым или мьютекс заблокированным. Если приложение завершилось, а файл не был закрыт надлежащим образом, это может привести к его разрушению или потере данных. Завершение потока после блокировки мьютекса надежно запирает доступ к критическому разделу, который находится под контролем этого мьютекса. Перед завершением поток должен выполнить некоторые действия очистительно-восстановительного характера, чтобы Н е допустить возникновения нежелательных ситуаций.
Модели создания и функционирования потоков
Цель потока— выполнить некоторую работу от имени процесса. Если процесс содержит несколько потоков, каждый поток выполняет некоторые подзадачи как части общей задачи, выполняемой процессом. Потокам делегируется работа в соответствии с конкретной стратегией, которая определяет, каким образом реализуется делегирование работы. Если приложение моделирует некоторую процедуру или объект, то выбранная стратегия должна отражать эту модель. Используются следующие распространенные модели:
• делегирование («управляющий-рабочий»);
• сеть с равноправными узлами;
• конвейер;
• «изготовитель-потребитель».
Каждая модель характеризуется собственной декомпозицией работ (Work Breakdown Structure — WBS), которая определяет, кто отвечает за создание потоков и при каких условиях они создаются. Например, существует централизованный подход, при котором один поток создает другие потоки и каждому из них делегирует некоторую работу. Существует также конвейерный (assembly-line) подход, при котором на различных этапах потоки выполняют различную работу. Созданные потоки могут выполнять одну и ту же задачу на различных наборах данных, различные задачи на одном и том же наборе данных или различные задачи на различных наборах данных. Потоки подразделяются на категории по выполнению задач только определенного типа. Например, можно создать группы потоков, которые будут выполнять только вычисления, только ввод или только вывод данных.
Возможны задачи, для успешного решения которых следует комбинировать перечисленные выше модели. В главе 3 мы рассматривали процесс визуализации. За-Дачи 1, 2 и 3 выполнялись последовательно, а задачи 4, 5 и 6 могли выполняться параллельно. Все задачи можно выполнить различными потоками. Если необходимо визуализировать несколько изображений, потоки 1, 2 и 3 могут сформировать конвейер. По завершении потока 1 изображение передается потоку 2, в то время к ак поток 1 может выполнять свою работу над следующим изображением. После буферизации изображений потоки 4, 5 и 6 могут реализовать параллельную обработку. Модель функционирования потоков представляет собой часть структурирования па раллелизма в приложении, в котором каждый поток может выполняться на отдельном процессоре. Модели функционирования потоков (и их краткое описание) приведены в табл. 4.4.
Таблица 4.4. Модели функционирования потоков
Модель
Описание
Модель делегирования
Модель с равно-правными узлами
Конвейер
Модель
«изготовитель-потребитель "
Центральный поток («управляющий») создает потоки («рабочие»), назначая каждому из них задачу. Управляющий поток может ожидать до тех пор, пока все потоки не завершат выполнение своих задач
Все потоки имеют одинаковый рабочий статус. Такие потоки называются равноправными Поток создает все потоки, необходимые для выполнения задач, но не осуществляет никакого делегирования ответственности. Равноправные потоки могут обрабатывать запросы от одного входного потока данных, разделяемого всеми потоками, или каждый поток может иметь собственный входной поток данных
Конвейерный подход применяется для поэтапной обработки потока входных данных. Каждый этап — это поток, который выполняет работу на некоторой совокупности входных данных. Когда эта совокупность пройдет все этапы, обработка всего потока данных будет завершена
Поток-«изготовитель» готовит данные , потребляемые потоком- «потребителем». Данные сохраняются в блоке памяти, разделяемом потоками — «изготовителем» и «потребителем»
Модель делегирования
В модели делегирования один поток («управляющий») создает потоки («рабочие») и назначает каждому из них задачу. Управляющему потоку нужно ожидать до тех пор, пока все потоки не завершат выполнение своих задач. Управляющий поток делегирует задачу, которую каждый рабочий поток должен выполнить, путем задания некоторой функции. Вместе с задачей на рабочий поток возлагается и ответственность за ее выполнение и получение результатов. Кроме того, на этапе получения результатов возможна синхронизация действий с управляющим (или другим) потоком.
Управляющий поток может создавать рабочие потоки в результате запросов, обращенных к системе. При этом обработка запроса каждого типа может быть делегирована рабочему потоку. В этом случае управляющий поток выполняет некоторый цикл событий. По мере возникновения событий рабочие потоки создаются и на них тут же возлагаются определенные обязанности. Для каждого нового запроса, обращенного к системе, создается новый поток. При использовании такого подхода процесс может превысить предельный объем выделенных ему ресурсов или предельное количество потоков. В качестве альтернативного варианта управляющий поток может создать пул потоков, которым будут переназначаться новые запросы. Управляющий поток создает во время инициализации некоторое количество потоков, а затем каждый поток приостанавливается до тех пор, пока не будет добавлен запрос в их очередь. По мере размещения запросов в очереди управляющий поток сигнализирует рабочему о необходимости обработки запроса. Как только поток справится со своей задачей, он извлекает из очереди следующий запрос. Если в очереди больше нет доступных запросов, поток приостанавливается до тех пор. пока управляющий поток не просигналит ему о появлении очередного задания в очереди. Если все рабочие потоки должны разделять одну очередь, то их можно
программировать на обработку запросов только определенного типа. Если тип запроса в очереди не совпадает с типом запросов, на обработку которых ориентирован данный поток, то он может снова приостановиться. Главная цель управляю-потока — создать все потоки, поместить задания в очередь и «разбудить» рабочие потоки, когда эти задания станут доступными. Рабочие потоки справляются о наличии запроса в очереди, выполняют назначенную задачу и приостанавливаются сами, если для них больше нет работы. Все рабочие и управляющий потоки выполняются параллельно. Описанные два подхода к построению модели делегирования представлены для сравнения на рис. 4.6.
Модель с равноправными узлами
Если в модели делегирования есть управляющий поток, который делегирует задачи рабочим потокам, то в модели с равноправными узлами все потоки имеют одинаковый рабочий статус. Несмотря на существование одного потока, который изначально создает все потоки, необходимые для выполнения всех задач, этот поток считается рабочим потоком, но он не выполняет никаких функций по делегированию задач. В этой модели нет никакого централизованного потока, но на рабочие потоки возлагается большая ответственность. Все равноправные потоки могут обрабатывать запросы из одного входного потока данных, либо каждый рабочий поток может иметь собственный входной поток данных, за который он отвечает. Входной поток данных может также храниться в файле или базе данных. Рабочие потоки могут нуждаться во взаимодействии и разделении ресурсов. Модель равноправных потоков представлена на рис. 4.7.