3. Разделение программы на несколько задач разного типа, отвечающих за создание других подзадач только определенного типа.
Эти способы реализации параллелизма отображены на рис. 3.13.
Например, эти методы реализации параллелизма можно применить к программе визуализации. Под визуализацией будем понимать процесс перехода от представления трехмерного объекта в форме записей базы данных в двухмерную теневую графическую проекцию на поверхность отображения (экран дисплея). Изображение представляется в виде теневых многоугольников, повторяющих форму объекта. Этапы визуализации показаны на рис. 3.14. Визуализацию можно разбить на ряд отдельных задач.
1. Установить структуру данных для сеточных моделей многоугольников.
2. Применить линейные преобразования.
3. Отбраковать многоугольники, относящиеся к невидимой поверхности.
4. Выполнить растеризацию.
5. Применить алгоритм удаления скрытых поверхностей.
6. Затушевать отдельные пиксели.
Первая задача состоит в представлении объекта в виде массива многоугольников, в котором каждая вершина многоугольника описывается в трехмерной мировой системе координат. Вторая задача — применить линейные преобразования к сеточной модели многоугольников. Эти преобразования используются для позиционирования объектов на сцене и создания точки обзора или поверхности отображения (области, которая видима наблюдателю с его точки обзора). Третья задача — отбраковать невидимые поверхности объектов на сцене. Это означает удаление линий, принадлежащих тем частям объектов, которые невидимы с точки обзора. Четвертая задача — преобразовать модель вершин в набор координат пикселей. Пятая задача — удалить любые скрытые поверхности. Если сцена содержит взаимодействующие объекты, например, когда одни объекты заслоняют другие, то скрытые (передними объектами) поверхности должны быть удалены. Шестая задача - наложить на поверхности изображения тень.
Рис. 3.13. Способы разбиения программы на отдельные задачи
Рис. 3.14. Этапы визуализации
Решение каждой задачи представляется в виде отдельного выполняемого файла. Первые три задачи (Taskl, Task2 и Task3) выполняются последовательно, а остальные три (Task4, Task5 и Task6)— параллельно. Реализация первого способа создания программы визуализации приведена в листинге 3.5.
// Листинг 3.5. Использование способа 1 для создания процессов
#include
#include
#include
#include
#include
#include
int main(void) {
posix_spawnattr_t Attr;
posix_spawn_file_actions_t FileActions;
char *const argv4[] = {«Task4»,...,NULL};
char *const argv5[] = {«Task5'\...,NULL};
char *const argv6[] = {«Task6»,...,NULL};
pid_t Pid;
int stat;
// Выполняем первые три задачи синхронно,
system(«Taskl . . . ") ;
system(«Task2 . . . ") ;
system(«Task3 . . . ") ;
//иниииализируем структуры
posix_spawnattr_init(&Attr);
posix_spawn_file_actions_init(&FileActions);
// execute last 3 tasks asynchronously
posix_spawn(&Pid,«Task4»,&FileActions,&Attr,argv4,NULL);
posix_spawn(&Pid,«Task5»,&FileActions,&Attr,argv5,NULL);
posix_spawn(&Pid,«Task6»,&FileActions,&Attr,argv6,NULL);
// like a good parent, wait for all your children
wait (&stat);
wait (&stat);
wait (&stat);
return(0);
}
В листинге 3.5 из функции main () с помощью функции system( ) вызываются на выполнение задачи Task1, Task2 и Task3. Каждая из них выполняется синхронно с родительским процессом. Задачи Task4, Task5 и Task6 выполняются асинхронно родительскому процессу благодаря использованию функций posix__spawn( ). Многоточие (... ) используется для обозначения файлов, требуемых задачам. Родительский процесс вызывает три функции wait (), и каждая из них ожидает завершения одной из задач (Task4, Task5 или Task6).
Используя второй способ, программу визуализации можно запустить из сценария командной оболочки. Преимущество этого сценария состоит в том, что он позволяет использовать все команды и операторы оболочки. В нашей программе визуализации для управления выполнением задач используются метасимволы & и &&.
Task1 ... && Task2 ... && Task3 Task4 . . . & Task5 . . . & Task6