unix-вилка-монитор-ребенок-прогресс - PullRequest
3 голосов
/ 17 марта 2009

У меня есть приложение, где немного параллельной обработки будет полезным. В целях обсуждения, допустим, есть каталог с 10 текстовыми файлами, и я хочу запустить программу, которая включает в себя 10 процессов, каждый из которых берет один из файлов и помещает его в верхний регистр. Я признаю, что родительская программа может ожидать завершения работы детей, используя одну из функций wait или функцию select .

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

Мой вопрос.

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

Ответы [ 6 ]

2 голосов
/ 18 марта 2009

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

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;
}

Обработка ошибок и т. Д. Для ясности.

2 голосов
/ 17 марта 2009

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

1 голос
/ 17 марта 2009

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

1 голос
/ 17 марта 2009

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

  • сигналы
  • fifos / именованные трубы
  • ВЫДЕРЖКА детей или другие пройденные ручки
  • очереди сообщений (при необходимости)
0 голосов
/ 17 марта 2009

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

0 голосов
/ 17 марта 2009

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

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