Параллельное и распределенное программирование на С++ (Хьюз, Хьюз) - страница 289

>int Value;

>pvm_stream MyStream;

>MyStream >> Value;

Поскольку каждый из рассмотренных операторных методов возвращает ссылку на тип pvm_stream , операторы вставки и извлечения можно соединить в цепочку.

>Mystream << Valuel << Value2;

>Mystream >> Value3 >> Value4;

Используя этот простой синтаксис, программист изолирован от более громоздкого синтаксиса функций pvm_send, pvm_pk, pvm_upk и pvm_recv . При этом он работает с более знакомыми для него объектно-ориентированными потоками данных. В данном случае поток данных представляет буфер сообщений, а элементы, которые помещаются в него или извлекаются оттуда, представляют сообщения, которыми обмениваются между собой PVM-процессы. Вспомните, что каждый PVM-процесс имеет отдельное адресное пространство. Поэтому операторы "<<" и ">>" не только маскируют вызовы функций pvm_send и pvm_recv, они также маскируют заложенную в них организацию связи. Поскольку класс pvm_stream можно использовать в много-поточной среде, операторы вставки и извлечения данных должны обеспечивать безопасность потоков выполнения.

Класс pvm_stream (см. рис. 11.4) содержит класс mutex. Класс mutex можно использовать для защиты критических разделов, которые имеются в классе pvm_stream. Класс pvm_stream инкапсулирует доступ к буферу отправки и буферу приема данных. Взаимодействие потоков выполнения и класса pvm_stream с буферами pvm_send и pvm_receive показано на рис. 11.5.

Рис.11.5. Взаимодействие потоков выполнения и класса pvm_stream с буферами pvm_send и pvm_receive

Критическими разделами являются не только буферы отправки и приема данных. Класс mios, используемый для хранения состояния класса pvm_stream, также является критическим разделом. Для защиты этого компонента можно использовать класс mutex.

При обращении к операторам вставки и извлечения данных можно использовать объект Mutex.

>// Листинг 11.15.

>//Определение операторов «<<» и «>>» для класса pvm_stream

>pvm_stream &pvm_stream::operator<<(int Data) {

>//.. .

>Mutex.lock(); reset();

>pvm_pkint(&Data,1,1); pvm_send(TaskId,MessageId); Mutex.unlock(); //.. .

>return(*this);

>}

>pvm_stream &pvm_stream::operator>>(int &Data) {

>int BufId; //. . .

>Mutex.lock();

>BufId = pvm_recv(TaskId,MessageId);

>StreamState = pvm_upkint(&Data,1,1);

>Mutex.unlock();

>//. . .

>return(*this);

>}

Этот вид защиты позволяет сделать класс pvm_stream безопасным. Здесь мы не представили код обработки исключений или другой код, который бы позволил предотвратить бесконечные отсрочки или взаимную блокировку. Основнал идея в данном случае — сделать акцент на компонентах и вариантах архитектуры, которые пригодны для поддержки параллелизма. Интерфейсный класс