Рекомендации, данные в этом разделе, относятся скорее к общей практике программирования, нежели параллельному программированию, как таковому. Тем не менее, думаю, что стоит заострить на них внимание.
Поскольку методы и способы параллельного программирования имеют отношение к "тяжелым" задачам, требующим большого времени счета, то вполне представима ситуация, когда потребуется по каким-то причинам досрочно, до получения окончательного результата, прервать счет. Например по причине истечения выделеного для работы на кластере времени. В случаях, когда параллельная программа выполняет периодическое сохранение данных на диск, весьма желательно осуществить такое прерывание аккуратно, способом, не приводящим к риску повреждения сохраненных данных. Риск повреждения данных связан с выбором момента времени прерывания. Если задача будет принудительно остановлена в тот самый момент, когда происходят файловые операции ввода-вывода, то есть большая вероятность, что данные сохранятся не полностью, что приведет к невозможности их дальнейшего использования.
Наибольшую актуальность корректное завершение программы приобретает в случае, когда для ее запуска используется менеджер ресурсов Torque, а для сохранения данных - локальная файловая система. Если остановить выполнение параллельной программы системными средствами Torque, то возникает не только риск нарушения целостности сохраненных данных, но и процедуры синхронизации сохраненных данных, которые должны быть запущены по завершению задачи, и которые прописаны в файле-задании Torque, выполнены не будут.
Наиболее простой в реализации способ принудительной остановки программы - это выставление семафоров. Семафор - это простой файл произвольного содержания (или без такового, то есть нулевой длины), наличие которого является сигналом остановки для программы. Наиболее безопасным с точки зрения сохранности данных моментом остановки является промежуток между окончанием очередного цикла итерации, за которым может следовать вызов процедуры сохранения данных, и началом следующего цикла. Рассмотрим фрагмент нашей тестовой программы решения уравнения теплопроводности.
33 c Получаем разницу значений функции на слоях 34 c с каждого узла кластера и находим максимальное значение 35 c этой разницы для всей разностной сетки 36 call MPI_REDUCE(df, gdf, 1, MPI_REAL8, 37 x MPI_MAX, 0, MPI_COMM_WORLD, ierr) 38 c Сообщаем найденную максимальную разницу 39 c всем узлам кластера 40 df=gdf 41 CALL MPI_BCAST(df, 1, MPI_REAL8, 0, MPI_COMM_WORLD, IERR) 42 c Выводим на экран разницу между итерациями 43 if ( myid .eq. 0 ) write(*,*) 'Diff:',df 44 c Если разница больше заданной, то решение не найдено 45 c и мы идем на следующий цикл 46 if (df .GT. 0.01) goto 1
Именно в этом месте предыдущий цикл итерации уже закончился, следующий еще не начался, а файловые операции, если они имели место в предыдущем цикле, так же уже завершены.
Обратим внимание на строку 40. В этом месте программы переменной df присваивается значение, на основе которого все процессы параллельной задачи принимают решение о необходимости продолжения счета. Логично будет именно в этом месте произвести проверку существования файла-семафора, и в случае его наличия занести в переменную df значение, останавливающее дальнейшие вычисления.
С учетом вышесказанного, фрагмент нашей программы приобретает следующий вид:
33 c Получаем разницу значений функции на слоях 34 c с каждого узла кластера и находим максимальное значение 35 c этой разницы для всей разностной сетки 36 call MPI_REDUCE(df, gdf, 1, MPI_REAL8, 37 x MPI_MAX, 0, MPI_COMM_WORLD, ierr) 38 c Сообщаем найденную максимальную разницу 39 c всем узлам кластера 40 df=gdf 40a c Проверяем существует ли глобальный файл-семафор 40b inquire(file="/etc/stop.stop", exist=ex) 40c if ( ex ) df=0.0 40d c Проверяем существует ли локальный файл-семафор 40e inquire(file="stop.stop", exist=ex) 40f if ( ex ) df=0.0 41 CALL MPI_BCAST(df, 1, MPI_REAL8, 0, MPI_COMM_WORLD, IERR) 42 c Выводим на экран разницу между итерациями 43 if ( myid .eq. 0 ) write(*,*) 'Diff:',df 44 c Если разница больше заданной, то решение не найдено 45 c и мы идем на следующий цикл 46 if (df .GT. 0.01) goto 1
Как вы заметили, мы проверяем два семафора (файлы с именем "stop.stop"): один, находящийся в общесистемном, каталоге, другой - в рабочей директории программы. Наличие хотя бы одного из них приводит к завершению вычислительного процесса. Первый файл, находящийся в каталоге /etc, может быть создан только тем, кто имеет в системе права суперпользователя. Наличие этого файла влияет на выполнение всех, запущенных на кластере параллельных задач, вне зависимости от того, какой у этих задач рабочий каталог и кому они принадлежат. Второй файл влияет на выполнение только той задачи, в рабочем каталоге которой этот файл находится. Создать такой файл может только владелец задачи.
Проверка двойного семафора сделана для удобства системного администратора, которому для остановки всех задач нет необходимости выяснять, какие задачи на данный момент запущены и в каких рабочих директориях.
Таким образом, для корректного завершения программы полюзователю необходимо любым удобным способом создать в рабочей директории программы файл с именем stop.stop. Администратор же (предполагаем, что кластер используется несколькими пользователями посредством менеджера Torque) для принудительного завершения всех параллельных задач и освобождения кластера может создать файл с таким же именем в системной директории /etc и минут через 10-20 выдать команду "qdel all" на случай, если кто-то не воспользовался рекомендацией проверять семафор /etc/stop.stop.