12.2. Процессы не хотят мигрировать!

Помогите, процесс XYZ не мигрирует. Ниже Moshe Bar постарался объяснить, почему одни процессы мигрируют, а другие нет. Тем не менее, предварительно загляните в /proc/$pid/, там может быть файл cantmove, который может подсказать вам, почему же определённый процесс не может мигрировать.

Также процесс может быть просто заблокирован. Чтобы это проверить, посмотрите файл:

cat /proc/$PID/lock

где $PID – это ID проблемного процесса.

А теперь посмотрим что говорит об этом сам Moshe.

Иногда подобные проблемы возникают при использовании одного ядра, но на разных дистрибутивах, к примеру, кластер из смешанных узлов под RedHat или Debian, а rc-скрипты, запускающие на них openMosix, немного различаются. Некоторые версии имеют сильно модифицированный /etc/inittab, запускающий все демоны (и их потомков) при помощи mosrun -h. Таким образом получается, что процессы не могут нормально мигрировать. Следовательно, все эти процессы имеют значение 1 в файле /proc/pid/lock при старте. Но можно заставить их мигрировать, записав 0 в этот файл.

Рассмотрим пример. Есть небольшая программа, которая должна мигрировать, если она запущена в количестве, превышающем количество процессоров на локальной машине. То есть, на двухпроцессорной SMP машине запуск программы в трёх экземплярах заставит её мигрировать, если другие узлы кластера по скорости хотя бы сопоставимы с локальной:

int main() { unsigned int i; while (1) { i++; } return 0; }

На процессоре Pentium 800Mhz она достигает переполнения довольно быстро.

А вот, к примеру, подобная программа никогда не будет мигрировать:

#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> ... key_t key; /* key to be passed to shmget() */ int shmflg; /* shmflg to be passed to shmget() */ int shmid; /* return value from shmget() */ int size; /* size to be passed to shmget() */ ... key = ... size = ... shmflg) = ... if ((shmid = shmget (key, size, shmflg)) == -1) { perror("shmget: shmget failed"); exit(1); } else { (void) fprintf(stderr, "shmget: shmget returned %d\n", shmid); exit(0); } ...

Программы, использующие каналы, тоже должны нормально мигрировать:

int pdes[2]; pipe(pdes); if (fork() == 0) { /* child */ close(pdes[1]); /* not required */ read(pdes[0]); /* read from parent */ ... } else { close(pdes[0]); /* not required */ write(pdes[1]); /* write to child */ ... }

Программы, использующие pthreads версии 2.4.17 и выше, не мигрируют, но, тем не менее, уже и не завершаются аварийно.

// // Very simple program demonstrating the use of threads. // // Command-line argument is P (number of threads). // // Each thread writes "hello" message to standard output, with // no attempt to synchronize. Output will likely be garbled. // #include <iostream> #include <cstdlib> // has exit(), etc. #include <unistd.h> // has usleep() #include <pthread.h> // has pthread_ routines // declaration for function to be executed by each thread void * printHello(void * threadArg); // ---- Main program ------------------------------------------------- int main(int argc, char* argv[]) { if (argc < 2) { cerr << "Usage: " << argv[0] << " numThreads\n"; exit(EXIT_FAILURE); } int P = atoi(argv[1]); // Set up IDs for threads (need a separate variable for each // since they're shared among threads). int * threadIDs = new int[P]; for (int i = 0; i < P; ++i) threadIDs[i] = i; // Start P new threads, each with different ID. pthread_t * threads = new pthread_t[P]; for (int i = 0; i < P; ++i) pthread_create(&threads[i], NULL, printHello, (void *) &threadIDs[i]); // Wait for all threads to complete. for (int i = 0; i < P; ++i) pthread_join(threads[i], NULL); // Clean up and exit. delete [] threadIDs; delete [] threads; cout << "That's all, folks!\n"; return EXIT_SUCCESS; } // ---- Code to be executed by each thread --------------------------- // pre: *threadArg is an integer "thread ID". // post: "hello" message printed to standard output. // return value is null pointer. void * printHello(void * threadArg) { int * myID = (int *) threadArg; cout << "hello, world, "; // pointless pause, included to make the effects of // synchronization (or lack thereof) more obvious usleep(10); cout << "from thread " << *myID << endl; pthread_exit((void*) NULL); }

Программы, использующие все виды файловых дескрипторов (описателей), включая и сокеты, также мигрируют (естественно, что сокеты не мигрируют вместе с процессом, а файлы мигрируют только при использовании oMFS/DFSA)

(весь вышеприведённый код написан Moshe, он же Moshe Bar, он же Moshe – CTO компании Qlusters, Inc.)

Пожалуйста, прочтите также man страницы openMosix, в них также содержится исчерпывающая информация о миграции процессов.

Если по какой-либо причине ваши процессы остаются запертыми, хотя по идее не должны бы, то попробуйте разрешить миграцию запертых процессов, добавив команду

# разрешает подпроцессам мигрировать на другие узлы echo 0 > /proc/self/lock

в файл /etc/profile.

[Warning]Внимание

Это позволит мигрировать всем процессам, а не тем, которые вы хотите. Для указания миграции определённых процессов используйте утилиту mosrun -l для разблокировки нужного процесса.