Domanda

Ho un'applicazione in cui un po 'di elaborazione parallela sarebbe utile. Ai fini della discussione, supponiamo che esista una directory con 10 file di testo e voglio avviare un programma, che elimina 10 processi, ognuno dei quali prende uno dei file e ne aumenta il contenuto. Riconosco che il programma genitore può attendere il completamento dei bambini utilizzando una delle funzioni aspetta o utilizzando la funzione seleziona .

Quello che vorrei fare è che il processo genitore controlli l'avanzamento di ogni processo biforcato e mostri qualcosa come una barra di avanzamento mentre i processi vengono eseguiti.

La mia domanda.

Quali potrebbero essere le alternative ragionevoli che ho per i processi biforcati per comunicare queste informazioni al genitore? Quali tecniche IPC sarebbe ragionevole usare?

È stato utile?

Soluzione

In questo tipo di situazione in cui si desidera monitorare solo l'avanzamento, l'alternativa più semplice è utilizzare la memoria condivisa. Ogni processo aggiorna il suo valore di avanzamento (ad es. Un numero intero) su un blocco di memoria condivisa e il processo principale legge il blocco regolarmente. Fondamentalmente, non è necessario alcun blocco in questo schema. Inoltre, si tratta di un "polling" applicazione di stile perché il master può leggere le informazioni ogni volta che lo desidera, quindi non è necessario alcun processo di elaborazione per la gestione dei dati di avanzamento.

Altri suggerimenti

Se l'unico progresso di cui hai bisogno è " quanti lavori sono stati completati? " ;, quindi un semplice

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

lo farà. Per riferire i progressi mentre, bene, in corso, ecco le stupide implementazioni di alcuni degli altri suggerimenti.

Tubi:

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

Memoria condivisa:

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

Gestione degli errori, ecc. per chiarezza.

Alcune opzioni (nessuna idea che, se ce n'è una, ti andrà bene - molto dipende da quello che stai effettivamente facendo, al contrario dei " maiuscoli dei file " analogia):

  • segnali
  • fifos / named pipe
  • STDOUT dei bambini o altre maniglie passate
  • code dei messaggi (se appropriato)

Se tutto ciò che desideri è un aggiornamento dei progressi, il modo di gran lunga più semplice è probabilmente usare una pipe anonima. La chiamata pipe (2) ti darà due descrittori di file, uno per ogni estremità della pipe. Chiamalo subito prima del fork e chiedi al genitore di ascoltare il primo fd e il figlio di scrivere al secondo. (Funziona perché sia ??i descrittori di file che l'array a due elementi che li contengono sono condivisi tra i processi - non memoria condivisa in sé, ma è copia su scrittura in modo che condividano i valori a meno che non li sovrascrivi.)

Proprio oggi qualcuno mi ha detto che usano sempre una pipe, tramite la quale i bambini possono inviare una notifica al processo genitore che tutto sta andando bene. Questa sembra una soluzione decente ed è particolarmente utile nei luoghi in cui si desidera stampare un errore, ma non si ha più accesso a stdout / stderr, ecc.

Boost.MPI dovrebbe essere utile in questo scenario. Puoi considerarlo eccessivo ma vale sicuramente la pena investigare:
www.boost.org/doc/html/mpi.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top