Пример с ошибкой демонстрирует, как кто-либо может принудительно завершать задачи и определять ситуации, когда задачи отрабатывают или завершаются ненормально. В данном примере порождаются несколько задач - так же, как это сделано в предыдущих примерах. Одна из них принудительно завершается предком. Поскольку интерес состоит в нахождении ненормальных завершений задач, после их порождения вызывается pvm_notify(). Вызовом pvm_notify() PVM приказывается передать вызывающей задаче сообщение о завершении работы определенных задач. В данном случае пользователя интересуют все потомки. Заметьте, что задача, вызывающая pvm_notify(), будет получать уведомления о ``прекращении существования'' задач, указанных в массиве их идентификаторов. Нет особого смысла передавать сообщение задаче, которая завершается. Вызов, связанный с извещениями, может также использоваться для информирования задач о том, что новый хост добавлен в виртуальную машину или удален из нее. Это применимо в ситуациях, когда программа стремится динамически адаптироваться к текущему состоянию сети.
После реализации запроса об уведомлениях задача-предок принудительно
завершает работу одного из потомков. Вызовом
pvm_kill()
принудительно завершается работа исключительно той задачи, чей идентификатор
передан как параметр. После завершения одной из порожденных
задач, предок с помощью
pvm_recv(-1, TASKDIED) ожидает сообщения,
уведомляющего о
``смерти'' этой задачи. Идентификатор задачи,
которая завершилась, передается в уведомительном сообщении в виде
одного целого числа. Процесс распаковывает идентификатор ``мертвой''
задачи и выводит его на экран. Хорошим стилем так же считается и вывод
заранее известного идентификатора завершаемой задачи. Эти идентификаторы
должны быть идентичны. Задачи-потомки просто ждут примерно по минуте
и затем спокойно завершаются.
Программа - пример failure.c:
Пример уведомления о сбое
Демонстрируется, как сообщать о фактах завершения задач
*/
/* определения и прототипы библиотеки PVM */
#include <pvm3.h>
/* максимальное число потомков, которые
будут порождаться этой программой */
#define MAXNCHILD 20
/* тег для использования в сообщениях, связанных
с отработкой задач */
#define TASKDIED 11
int
main(int argc, char* argv[])
{
/* количество задач для порождения,
3 используются по умолчанию */
int ntask = 3;
/* код возврата для вызовов PVM */
int info;
/* свой идентификатор задачи */
int mytid;
/* свой идентификатор задачи-предка */
int myparent;
/* массив идентификаторов задач-потомков */
int child[MAXNCHILD];
int i, deadtid;
int tid;
char *argv[5];
/* поиск своего идентификатора задачи */
mytid = pvm_mytid();
/* проверка на ошибки */
if (mytid < 0) {
/* вывод на экран сообщения об ошибке */
pvm_perror(argv[0]);
/* выход из программы */
return -1;
}
/* нахождение числа-идентификатора задачи-предка */
myparent = pvm_parent();
/* выход, если есть ошибки, но не PvmNoParent */
if ((myparent < 0) && (myparent != PvmNoParent)) {
pvm_perror(argv[0]);
pvm_exit();
return -1;
}
/* если предок не найден, то это и есть предок */
if (myparent == PvmNoParent) {
/* определение числа задач для порождения */
if (argc == 2) ntask = atoi(argv[1]);
/* удостоверение, что ntask - допустимо */
if ((ntask < 1) || (ntask > MAXNCHILD)) {pvm_exit();
return 0; }
/* порождение задач-потомков */
info = pvm_spawn(argv[0], (char**), PvmTaskDebug,
(char*)0, ntask, child);
/* удостоверение, что порождение произошло успешно */
if (info != ntask) { pvm_exit(); return -1; }
/* вывод на экран идентификаторов задач */
for (i = 0; i < ntask; i++) printf("t%x\t",child[i]);
putchar('\n');
/* запрос об уведомлении о завершении потомка */
info = pvm_notify(PvmTaskExit, TASKDIED, ntask,
child);
if (info < 0) { pvm_perror("notify"); pvm_exit();
return -1; }
/* уничтожение потомка со ``средним''
идентификатором */
info = pvm_kill(child[ntask/2]);
if (info < 0) { pvm_perror("kill"); pvm_exit();
return -1; }
/* ожидание уведомления */
info = pvm_recv(-1, TASKDIED);
if (info < 0) { pvm_ perror("recv"); pvm_exit();
return -1; }
info = pvm_upkint(&deadtid, 1, 1);
if (info < 0) pvm_perror("calling pvm_upkint");
/* должен быть потомок со ``средним'' номером */
printf("Задача t%x завершилась.\n", deadtid);
printf("Задача t%x является средним потомком.\n",
child[ntask/2]);
pvm_exit();
return 0;
}
/* это потомок */
sleep(63);
pvm_exit();
return 0;
}