next up previous contents
Next: Обработка ошибок ввода-вывода Up: Семантика непротиворечивости Previous: Размер файла   Contents

Примеры непротиворечивости и семантики

Примеры в этом разделе иллюстрируют приложения гарантий непротиворечивости и семантики MPI. Они показывают

Простейшим способом достижения непротиворечивости для конфликтующих попыток доступа является получение последовательной непротиворечивости при установке атомарного режима. В программе, приведенной ниже, процесс 1 читает 0 или 10 целых чисел. В последнем случае, каждый элемент b станет равен 5. Если установлен неатомарный режим, результаты чтения будут неизвестны. /* Process 0*/
int i, a[10];
int TRUE = 1;

for(i=0;i<10;i++)
a[i] = 5;
_File_open(MPI_COMM_WORLD, ``workfile'',
MPI_MODE_RDWR | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh0 );
_File_set_view( fh0, 0, MPI_INT, MPI_INT, ``native'',
MPI_INFO_NULL );
MPI_File_set_atomicity( fh0, TRUE );
MPI_File_write_at(fh0, 0, a, 10, MPI_INT, &status);
/* MPI_Barrier( MPI_COMM_WORLD ) ;*/

/* Process 1 */
int b[10];
int TRUE = 1;
MPI_File_open(MPI_COMM_WORLD, ``workfile'',
MPI_MODE_RDWR | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh1 );
_File_set_view( fh1, 0, MPI_INT, MPI_INT, ``native'',
MPI_INFO_NULL );
MPI_File_set_atomicity( fh1, TRUE ) ;
/* MPI_Barrier( MPI_COMM_WORLD ) ; */
MPI_File_read_at(fhl, 0, b, 10, MPI_INT, &status);
Пользователь может гарантировать, что запись в процессе 0 предшествует чтению в процессе 1, вводя временной порядок, например, вызовами MPI_BARRIER(комментированными в приведенном выше коде).

Совет пользователям: Для установления временного порядка можно использовать процедуры, иные, чем MPI_BARRIER. В примере, приведенном выше, процесс 0 мог бы использовать MPI_SEND для отсылки сообщения длиной 0 байт, которое принимается процессом 1, используя MPI_RECV.[]

С другой стороны, пользователь может ввести непротиворечивость при установленном неатомарном режиме:

/* Process 0 */
int i, a[10];
for (i=0;i<10;i++)
a[i] = 5;

_File_open(MPI_COMM_WORLD,``workfile'',
MPI_MODE_RDWR | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh0 );
_File_set_view(fh0, 0, MPI_INT, MPI_INT,
SPMgt;``native'', MPI_INFO_NULL);
MPI_File_write_at(fh0, 0, a, 10, MPI_INT, &status) ;
MPI_File_sync( fh0 ) ;
MPI_Barrier( MPI_COMM_WORLD ) ;
MPI_File_sync( fh0 ) ;

/* Process 1 */
int b[10] ;
MPI_File_open( MPI_COMM_WORLD, ``workfile'',
MPI_MODE_RDWR | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh1 ) ;
_File_set_view( fh1, 0, MPI_INT, MPI_INT,
SPMgt;``native'', MPI_INFO_NULL ) ;
MPI_File_sync( fh1 ) ;
MPI_Barrier( MPI_COMM_WORLD) ;
MPI_File_sync( fh1 ) ;
MPI_File_read_at(fh1, 0, b, 10, MPI_INT, &status);

Конструкция ``sync-barrier-sync'' требуется, поскольку:

Следующая программа представляет ошибочный способ достижения непротиворечивости при удалении кажущегося лишним второго вызова ``sync'' в каждом процессе.

/* - - - - - - - - - - ЭТОТ ПРИМЕР СОДЕРЖИТ ОШИБКУ - - - - - - - - - - */
/* Process 0 */
int i, a[10];
for(i=0;i<10;i++)
a[i] = 5;

_File_open( MPI_COMM_WORLD, ``workfile'',
MPI_MODE_RDWR | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh0 );
_File_set_view( fh0, 0, MPI_INT, MPI_INT,
SPMgt;``native'', MPI_INFO_NULL);
MPI_File_write_at(fh0, 0, a, 10, MPI_INT, &status) ;
MPI_File_sync( fh0 ) ;
MPI_Barrier( MPI_COMM_WORLD ) ;

/* Process 1 */
int b[10] ;
_File_open( MPI_COMM_WORLD, ``workfile'',
MPI_MODE_RDWR | MPI_MODE_CREATE,
MPI_INFO_NULL, &fh1 ) ;
_File_set_view( fh1, 0, MPI_INT, MPI_INT,
SPMgt;``native'', MPI_INFO_NULL ) ;
MPI_Barrier( MPI_COMM_WORLD ) ;
MPI_File_sync( fh1 ) ;
MPI_File_read_at(fh1, 0, b, 10, MPI_INT,&status);
/* - - - - - - - - - - ЭТОТ ПРИМЕР СОДЕРЖИТ ОШИБКУ - - - - - - - - - - - */

Приведенная выше программа также нарушает правило MPI, запрещающее неупорядоченные коллективные операции и блокируется в реализациях, у которых MPI_FILE_SYNC блокирующая.

Совет пользователям: Некоторые реализации могут выбрать способ выполнения
MPI_FILE_SYNC как временно синхронизирующей функции. В этом случае, приведенная выше конструкция ``sync-barrier-sync'' может быть заменена одним ``sync''. Однако, такой код не будет перено-
симым.[]



Асинхронный ввод-вывод.    Поведение операций асинхронного ввода-вывода определяется применением правил, определенных выше для синхронных операций ввода-вывода.

В следующих примерах производится доступ к уже существующему файлу ``myfile''. Слово 10 в ``myfile'' первоначально содержит целое значение 2. Каждый пример записывает, а затем читает слово 10.

Вначале рассмотрим следующий фрагмент кода:

int a = 4, b, TRUE=1;
MPI_File_open( MPI_COMM_WORLD, ``myfile'',
MPI_MODE_RDWR, MPI_INFO_NULL, &fh ) ;
_File_set_view( fh, 0,MPI_INT, MPI_INT, ``native'',
MPI_INFO_NULL );
/* MPI_File_set_atomicity( fh, TRUE ) ;
Используйте это для установки атомарного режима.*/
MPI_File_iwrite_at(fh, 10, &a, 1, MPI_INT, &reqs[0]) ;
MPI_File_iread_at(fh, 10, &b, 1, MPI_INT, &reqs[l]) ;
MPI_Waitall(2, reqs, statuses) ;

Для операций асинхронного доступа к данным MPI определяет, что доступ происходит в любое время между вызовом процедуры асинхронного доступа к данным и завершением соответсвующей процедуры, выполняющей запрос. Поэтому выполнение чтения перед записью или записи перед чтением является непротиворечивым с порядком программы. Если установлен атомарный режим, MPI гарантирует последовательную непротиворечивость, и программа будет считывать из b либо 2, либо 4. Если атомарный режим не установлен, то последовательная непротиворечивость не гарантируется, и программа может иногда считывать что-либо иное, нежели 2 или 4 из-за конфликтов при доступе к данным.

Подобным образом, следующий фрагмент кода не упорядочивает доступ к файлу: int a = 4, b, TRUE=1;
MPI_File_open( MPI_COMM_WORLD, ``myfile'',
MPI_MODE_RDWR, MPI_INFO_NULL, &fh ) ;
_File_set_view( fh, 0, MPI_INT, MPI_INT, ``native'',
MPI_INFO_NULL );
/* MPI_File_set_atomicity( fh, TRUE ) ;
Используйте это для установки атомарного режима.*/
MPI_File_iwrite_at(fh, 10, &a, 1, MPI_INT, &reqs[0]) ;
MPI_File_iread_at(fh, 10, &b, 1, MPI_INT, &reqs[l]) ;
MPI_Wait(&reqs[0], &status) ;
MPI_Wait(&reqs[l], &status) ;

Если установлен атомарный режим, либо 2, либо 4 будет считываться из b. И вновь, MPI не гарантирует последовательную непротиворечивость в неатомарном режиме.

С другой стороны, следующий фрагмент кода: int a = 4;
int b;
MPI_File_open(MPI_COMM_WORLD, ``myfile'',
MPI_MODE_RDWR, MPI_INFO_NULL, &fh ) ;
_File_set_view( fh, 0, MPI_INT, MPI_INT, ``native'',
MPI_INFO_NULL );
/* MPI_File_set_atomicity( fh, TRUE ) ;
Используйте это для установки атомарного режима.*/
MPI_File_iwrite_at(fh, 10, &a, 1, MPI_INT, &reqs[0]) ;
MPI_Wait(&reqs[0], &status) ;
MPI_File_iread_at(fh, 10, &b, 1, MPI_INT, &reqs[l]) ;
MPI_Wait(&reqs[l], &status) ;

определяет тот же порядок, что и:

int a = 4, b;
MPI_File_open( MPI_COMM_WORLD, ``myfile'',
MPI_MODE_RDWR, MPI_INFO_NULL, &fh ) ;
_File_set_view( fh, 0, MPI_INT, MPI_INT, ``native'',
MPI_INFO_NULL );
/* MPI_File_set_atomicity( fh, TRUE ) ;
Используйте это для установки атомарного режима.*/
MPI_File_write_at(fh, 10, &a, 1, MPI_INT, &reqs[0]) ;
MPI_File_read_at(fh, 10, &b, 1, MPI_INT, &reqs[l]) ;

Поскольку

MPI гарантирует, что оба фрагмента программы будут считывать из b значение 4. В этом примере не нужно устанавливать атомарный режим.

Такие же рассуждения применяются к конфликтующим потыткам доступа в форме: MPI_File_write_all_begin(fh,...) ;
MPI_File_iread(fh,...) ;
MPI_Wait(fh,...) ;
MPI_File_write_all_end(fh,...) ;

Помните, что ограничения, управляющие непротиворечивостью и семантикой, не относятся к следующему:

MPI_File_write_all_begin(fh,...) ;
MPI_File_read_all_begin(fh,...) ;
MPI_File_read_all_end(fh,...) ;
MPI_File_write_all_end(fh,...) ;

поскольку раздельные коллективные операции над одним и тем же дескриптором файла могут не перекрываться (см. раздел 7.4.5).


next up previous contents
Next: Обработка ошибок ввода-вывода Up: Семантика непротиворечивости Previous: Размер файла   Contents
Alex Otwagin 2002-12-10