Pergunta

Eu tenho uma aplicação onde um pouco de processamento paralelo seria de benefício. Para efeitos da discussão, digamos que há um diretório com 10 arquivos de texto na mesma, e quero iniciar um programa, que garfos Off 10 processos, cada uma tomada dos arquivos, e maiúscula o conteúdo do arquivo. Eu reconheço que o programa pai pode esperar que as crianças a completar usando um dos espera funções, ou usando o selecione função .

O que eu gostaria de fazer é ter monitorar o processo pai o andamento de cada processo de mentiroso, e exibir algo como uma barra de progresso como os processos são executados.

minha pergunta.

O que seria uma alternativas razoáveis ??que eu tenho para os processos bifurcados para comunicar isso de volta informações para o pai? Que técnicas IPC seria razoável uso?

Foi útil?

Solução

Neste tipo de situação onde você só deseja monitorar o progresso, a alternativa mais fácil é usar memória compartilhada. Todo processo de atualiza-lo progredir valor (por exemplo, um inteiro) em um bloco de memória compartilhada, eo processo mestre lê o bloco regularmente. Basicamente, você não precisa de qualquer bloqueio neste esquema. Além disso, é um "polling" aplicação estilo, porque o mestre pode ler as informações sempre que quiser, para que você não precisa de qualquer processamento de eventos para lidar com os dados de progresso.

Outras dicas

Se o único progresso que você precisa é "quantos postos de trabalho ter concluído?", Então um simples

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

vai fazer. Para relatar o progresso enquanto, bem, em andamento, aqui está implementações mudos de algumas das outras sugestões.

Pipes:

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

memória compartilhada:

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

Tratamento de erros etc. elidido para maior clareza.

Algumas opções (nenhuma idéia que, se houver, vai servi-lo - muito depende do que você está realmente fazendo, como op à analogia "maiúscula arquivos"):

  • sinais
  • fifos / pipes
  • o STDOUT dos filhos ou outras alças passadas
  • filas de mensagens (se apropriado)

Se tudo que você quer é uma atualização de progresso, de longe a maneira mais fácil é provavelmente usar um pipe anônimo. O (2) chamada tubo irá dar-lhe dois descritores de arquivos, um para cada extremidade do tubo. Chamá-lo um pouco antes de garfo, e ter o pai ouvir a primeira fd ea gravação criança para o segundo. (Isso funciona porque ambos os descritores de arquivo e a matriz de dois elementos que os contenham são compartilhados entre os processos -. Não memória compartilhada per se, mas é copy-on-write para que eles compartilham os valores a menos que você substituí-los)

Apenas mais cedo hoje alguém me disse que eles sempre usam um tubo, através do qual as crianças podem enviar uma notificação para o processo pai que tudo está indo bem. Esta parece ser uma solução decente, e é especialmente útil em lugares onde você gostaria de imprimir um erro, mas já não têm acesso a stdout / stderr, etc.

Boost.MPI deve ser útil neste cenário. Você pode considerar um exagero, mas é definitivamente vale a pena investigar:
www.boost.org/doc/html/mpi.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top