2009-03-16 6 views
3

У меня есть приложение, в котором бит параллельной обработки будет полезен. Для целей обсуждения предположим, что в нем есть каталог с 10 текстовыми файлами, и я хочу запустить программу, которая разворачивает 10 процессов, каждый из которых берет один из файлов, а верхний - содержимое файла. Я признаю, что родительская программа может дождаться завершения работы детей с использованием одной из функций или с помощью выберите функцию.unix-fork-monitor-child-progress

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

Мой вопрос.

Каковы были бы разумные альтернативы для разветвленных процессов для передачи этой информации родителям? Какие методы МПК разумно использовать?

ответ

2

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

+0

Если значение прогресса многобайтовое, вам может потребоваться блокировка (в зависимости от всех видов вещей из кеша для выравнивания ...). Раньше это называлось «проблемой одометра»; в основном (и в десятичном значении с большой буквы), начиная с 1999 по 2000 год, читатель мог видеть 1900, 2099 и т. д. – MarkusQ

0

Как-то раньше кто-то сказал мне, что они всегда используют трубку, по которой дети могут отправлять уведомление родительскому процессу, что все идет хорошо. Это кажется достойным решением и особенно полезно в тех местах, где вы хотите распечатать ошибку, но больше не имеете доступа к stdout/stderr и т. Д.

1

Несколько вариантов (не знаю, какая из них, если таковые имеются, подходят вы - очень многое зависит от того, что вы на самом деле делают, так как опнутым к «верхний регистр файлов» аналогии): сигналы

  • FIFOs/именованные каналы
  • стандартный вывод из детей или других прошли ручки
  • очереди сообщений (при необходимости)
0

Boost.MPI должен быть полезен в этом сценарии. Вы можете считать это излишним, но это, безусловно, заслуживает изучения:
www.boost.org/doc/html/mpi.html

1

Если все, что вы хотите это обновление прогресс, безусловно, самый простой способ, вероятно, использовать анонимный труба. Вызов pipe (2) даст вам два дескриптора файла, по одному для каждого конца канала. Вызовите его прямо перед вилкой, и родитель прислушивается к первому fd, а дочерний - ко второму. (Это работает потому, что и файловые дескрипторы, и двухэлементный массив, содержащий их, совместно используются между процессами - не разделяемая память как таковая, а копируются на запись, поэтому они делят значения, если вы их не перезаписываете.)

2

Если только прогресс вам нужно, это «сколько завершенные работы?», то простой

while (jobs_running) { 
    pid = wait(&status); 
    for (i = 0; i < num_jobs; i++) 
     if (pid == jobs[i]) { 
      jobs_running--; 
      break; 
     } 
    printf("%i/%i\n", num_jobs - jobs_running, num_jobs); 
} 

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

Трубы

#include <poll.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include <unistd.h> 

int child(int fd) { 
    int i; 
    struct timespec ts; 
    for (i = 0; i < 100; i++) { 
     write(fd, &i, sizeof(i)); 
     ts.tv_sec = 0; 
     ts.tv_nsec = rand() % 512 * 1000000; 
     nanosleep(&ts, NULL); 
    } 
    write(fd, &i, sizeof(i)); 
    exit(0); 
} 

int main() { 
    int fds[10][2]; 
    int i, j, total, status[10] = {0}; 
    for (i = 0; i < 10; i++) { 
     pipe(fds[i]); 
     if (!fork()) 
      child(fds[i][1]); 
    } 
    for (total = 0; total < 1000; sleep(1)) { 
     for (i = 0; i < 10; i++) { 
      struct pollfd pfds = {fds[i][0], POLLIN}; 
      for (poll(&pfds, 1, 0); pfds.revents & POLLIN; poll(&pfds, 1, 0)) { 
       read(fds[i][0], &status[i], sizeof(status[i])); 
       for (total = j = 0; j < 10; j++) 
        total += status[j]; 
      } 
     } 
     printf("%i/1000\n", total); 
    } 
    return 0; 
} 

Общая память:

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

int child(int *o, sem_t *sem) { 
    int i; 
    struct timespec ts; 
    for (i = 0; i < 100; i++) { 
     sem_wait(sem); 
     *o = i; 
     sem_post(sem); 
     ts.tv_sec = 0; 
     ts.tv_nsec = rand() % 512 * 1000000; 
     nanosleep(&ts, NULL); 
    } 
    sem_wait(sem); 
    *o = i; 
    sem_post(sem); 
    exit(0); 
} 

int main() { 
    int i, j, size, total; 
    void *page; 
    int *status; 
    sem_t *sems; 
    size = sysconf(_SC_PAGESIZE); 
    size = (10 * sizeof(*status) + 10 * sizeof(*sems) + size - 1) & size; 
    page = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 
    status = page; 
    sems = (void *)&status[10]; 
    for (i = 0; i < 10; i++) { 
     status[i] = 0; 
     sem_init(&sems[i], 1, 1); 
     if (!fork()) 
      child(&status[i], &sems[i]); 
    } 
    for (total = 0; total < 1000; sleep(1)) { 
     for (total = i = 0; i < 10; i++) { 
      sem_wait(&sems[i]); 
      total += status[i]; 
      sem_post(&sems[i]); 
     } 
     printf("%i/1000\n", total); 
    } 
    return 0; 
} 

Обработка ошибок и т.д. опущены для ясности.