Вопрос

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

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

Мой вопрос.

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

Это было полезно?

Решение

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

Другие советы

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

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

Обработка ошибок и т.д.исключено для ясности.

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top