class POArray
{
friend CCVoid& operator<<(CCVoid&, const POArray&);
friend CCVoid& operator>>(CCVoid&, POArray&);
public:
void init(int, char * []);
virtual POArrayNode *global create_pobj(proc_t)=0;
POArrayNode *global pobjs[];
int posize;
};
global class POArrayNode
{
friend class POArray;
public:
virtual void init_pobj(POArray&)=0;
POArray *p_array;
};
void POArray::init(int sz, char *nodelist[])
{
posize = sz;
// Создаются новые процессорные объекты
pobjs = new (POArrayNode *global)[posize];
parfor (int i=0; i<posize; i++)
{
proc_t loc(node_t(nodelist[i] ));
pobjs[i] = create_pobj(loc);
}
// Копирование указателей процессорных объектов
parfor (intj=0; j<posize; j++) // в новые процессорные
pobjs[j]->init_pobj(*this); //объекты
}
Можно более искусно использовать класс POArray для создания процессорных объектов произвольного типа. Нужно сделать функции create_pobj и init_pobj виртуальными, для чего они должны быть объявлены с ключевым словом virtual и дополнены знаком присвоения нуля (=0). Благодаря этому, эти функции могут быть определены в классах, полученных соответственно из классов POArrary и POArrayNode.
Для создания массива виртуальных функций, например, типа T, необходимо просто вывести новые классы из классов POArrary и POArrayNode и в этих классах определить функции create_pobj и init_pobj. Теперь эти производные (дочерние) функции будут создавать и инициализировать новые процессорные объекты типа T.
Текст 3.11 является фрагментом программы, в котором описана параллельная структура двух взаимодействующих вычислительных моделей, представленных классами POArray иAtmOcn. Каждая из моделей использует половину (P/2) процессоров.
В этом тексте из класса POArray получается классAtmOcn, который дополняется определением виртуальной функции create_pobj, использованной в POArray для создания процессорного объекта, и определениями вычислительных функций atmosphere и ocean, представляющих собственно некие программные модели
Аналогично, класс процессорного объекта AtmOcnNode, выведенный из POArrayNode, определяет виртуальную функцию init_pobj, которая инициализирует процессорный объект объединенной модели, и определяет функции atm_proc и ocn_proc, которые будут выполняться в каждом процессорном объекте.
Функция init_pobj создает локальный образец объекта AtmOcn, переданного как параметр, обеспечивая тем самым каждый процессорный объект доступом к другим процессорным объектам.
globalclassAtmOcnNode: publicPOArrayNode
{
public:
voidatm_proc(int); // Процедура вычислений
void ocn_proc(int); // Процедура вычислений
void init_pobj(POArray& ar) // Операция инициализации
{
p_array = new AtmOcn(ar);
}
};
class AtmOcn: public POArray
{
public:
void atmosphere();
void ocean();
AtmOcn(const POArray& ar): POArray(ar) { . . . };
POArrayNode *global create_pobj(proc_t locn)
{
return new (locn) AtmOcnNode;
}
};
void AtmOcn::atmosphere()
{
parfor (int j=0; j<posize; j++)
((AtmOcnNode *global) pobjs[j])->atm_proc(j);
}
void atm_proc(int id)
{
. . . // Ядро вычислительного кода модели
}
void main(int argc, char *argv[])
{
int P = atoi(argv[l]);
char *nodes[] = read_nodes();
AtmOcn atm, ocn;
atm.init(P/2, nodes); // P принято четным
ocn.init(P/2, &nodes[P/2]);
par
{
atm.atmosphere();
ocn.ocean();
}
}
Преимущество структурного решения в тексте 3.11 состоит в том, что задача отображения определена отдельно от других видов программной логики. И наконец, эта программа может быть представлена композицией двух взаимодействующих моделей на тех же самых процессорах. Для этого достаточно просто изменить обращения к init в главной программе, как показано в тексте 3.12.
void main(int argc, char *argv[])
{
int P = atoi(argv[1]);
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.