2009-02-27 4 views
3

У меня есть родитель с 5 дочерними процессами. Я хочу отправить случайную переменную в каждый дочерний процесс. Каждый дочерний элемент будет смещать переменную и отправлять ее обратно родительскому объекту, и родитель суммирует их все вместе.Как сделать несколько взаимодействующих процессов fork() с помощью совместно используемой памяти?

Возможно ли это? Я не могу понять это ...

edit: этот процесс будет использовать разделяемую память.

ответ

6

Существует множество способов сделать это, все из которых связаны с некоторой формой межпроцессного взаимодействия. Какой из них будет зависеть от многих факторов, но некоторые из них:

  • общая память. (popen).
  • розетки.

В общем, я бы, вероятно, popen провел несколько сеансов связи в родительском доме до появления детей; родитель узнает обо всех пяти, но каждый ребенок может быть настроен на использование только одного.

Общая память также возможность, хотя вы, вероятно, придется иметь несколько значений в нем каждого ребенка, чтобы обеспечить связь прошло гладко:

  • значение для сохранения значения переменной и возврата.
  • значение для сохранения состояния (0 = начало, 1 = переменная готова для ребенка, 2 = переменная готова для родителя снова).

Во всех случаях детям необходимо только получить свои ценности, а не те, которые предназначены для других детей. Это может быть так же просто, как добавление значения в блок разделяемой памяти для хранения PID дочернего элемента. Все дети будут сканировать каждый элемент в блоке, но будут обрабатывать только те, где состояние равно 1, а PID - их PID.

Например:

  • Main создает разделяемую память для пяти детей. Каждый элемент имеет состояние, PID и значение.
  • Главное задает все состояния, чтобы «начать».
  • Главное начинает пять детей, которые все подключаются к общей памяти.
  • Главное хранилище всех своих ПИД.
  • Все дети начинают сканирование разделяемой памяти для состояния = «готовы для ребенка» и их PID.
  • Main помещает первый элемент (state = "ready for child", PID = pid1, value = 7).
  • Main помещает второй элемент (state = "ready for child", PID = pid5, value = 9).
  • Ребенок pid1 берет первый элемент, меняет значение на 49, устанавливает состояние «готов к родительскому»), возвращается к мониторингу.
  • Ребенок pid5 берет второй элемент, меняет значение на 81, устанавливает состояние «готов к родительскому»), возвращается к мониторингу.
  • Главное забирает ответ pid5, устанавливает, что состояние возвращается в "start.
  • Главный подхватывает ответ ПИД1, в устанавливает, что состояние обратно «начать.

Это дает меру параллельности с каждым ребенком постоянного мониторинга общей памяти для работы это означало сделать, основные места работы там и периодически получает результаты

+0

Я бы использовал общую память – kylex

+0

Возможно, вам не нужно делать сканирование; дети получают копию родительских данных процесса, поэтому (в отличие от примера vfork()) дети могут смотреть на счетчик, который сообщает им, какая запись принадлежит им. Вы можете предварительно загрузить память со случайными значениями; то дети знают, что данные готовы. –

+0

Это будет работать, если вы просто используете fork (с родительским и дочерним кодом в одном и том же исполняемом файле), но не если вы выполняете команду для ввода дочернего элемента: пространство процесса перезаписывается (включая счетчик). В большинстве случаев не происходит много опасных вещей, которые разделяются между двумя вилами. Тем не менее, это вариант. – paxdiablo

3

скверный метод использует vfork() и позволяет различные дети топчут на разные части памяти перед выходом, родитель, то просто суммирует модифицированные биты памяти

Высоко unrecommended - но о.. только случай, когда я меня там, где vfork() может действительно использовать.

Только для развлечений (шахты) я закодированы это вверх:

#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <time.h> 
#include <sys/wait.h> 

int main(void) 
{ 
    int i; 
    int array[5]; 
    int square[5]; 
    long sum = 0; 

    srand(time(0)); 
    for (i = 0; i < 5; i++) 
    { 
     array[i] = rand(); 
     if (vfork() == 0) 
     { 
      square[i] = array[i] * array[i]; 
      execl("/bin/true", "/bin/true", (char *)0); 
     } 
     else 
      wait(0); 
    } 

    for (i = 0; i < 5; i++) 
    { 
     printf("in: %d; square: %d\n", array[i], square[i]); 
     sum += square[i]; 
    } 
    printf("Sum: %d\n", sum); 
    return(0); 
} 

Это работает. Предыдущая версия с использованием «exit(0)» вместо «execl()» не работает; квадратная матрица была равна нулю. Пример вывод (32-битная компиляция на Solaris 10, SPARC):

in: 22209; square: 493239681 
in: 27082; square: 733434724 
in: 2558; square: 6543364 
in: 17465; square: 305026225 
in: 6610; square: 43692100 
Sum: 1581936094 

Иногда сумма переполняется - есть много возможностей для улучшения обработки этого.

страница

Солярис руководство для 'vfork() говорит:

В отличие от функции вилки(), дочерний процесс заимствует память родителя и поток управления до вызова execve() или выход (либо ненормально, либо по вызову _exit() (см. exit (2)). Любая модификация, сделанная во время этого времени в любую часть памяти в дочернем процессе, отражается в родительском процессе при возврате из vfork() Родительский процесс приостанавливается, пока ребенок использует его ресурсы.

Это, вероятно, означает, что «wait()» не нужен в моем коде. (Тем не менее, попытка упростить код, казалось, заставила его вести себя неопределенно. Очень важно, чтобы i не менялся преждевременно: wait() действительно гарантирует, что синхронизация. Использование _exit() вместо execl() также, казалось, нарушало ситуацию. Не используйте vfork(), если вы цените свое здравомыслие - или если вам нужны какие-либо отметки для вашей домашней работы.)

+0

Интересно. Кстати, вам также не нужен pid_t pid. В Mac OS X я также получаю неверные результаты. Он напечатал 2 блока вывода, и некоторые из квадратов были явно неправильными. После второго блока вывода процесс зависает (но без циклов).Однако не пытались его отладить. –

+0

@Craig S: yup - вы правы насчет pid. Это от похмелья от эксперимента при отладке. Я удалю его. По сути, vfork() - зло; Я удивлен, что нашел для него потенциал (но не хороший!). –

+0

Да, и vfork() также не очень портативен. Забавно видеть это в действии. Возможно, завтра я придумаю собственное решение, которое работает на Mac OS X. Я также задаюсь вопросом, что произойдет, если вы вызовете _exit(), а не exit() вместо exec'ing/bin/true. –

0

Такие вещи, как the anti thread, могут сделать это немного легче для вас, см. примеры (в частности, программу поиска ns).

+0

Кажется интересным, но ссылка не работает ... –