Domanda

Ti preghiamo di considerare il seguente pseudo-codice fork () / SIGCHLD .

  // main program excerpt
    for (;;) {
      if ( is_time_to_make_babies ) {

        pid = fork();
        if (pid == -1) {
          /* fail */
        } else if (pid == 0) {
          /* child stuff */
          print "child started"
          exit
        } else {
          /* parent stuff */
          print "parent forked new child ", pid
          children.add(pid);
        }

      }
    }

  // SIGCHLD handler
  sigchld_handler(signo) {
    while ( (pid = wait(status, WNOHANG)) > 0 ) {
      print "parent caught SIGCHLD from ", pid
      children.remove(pid);
    }
  }

Nell'esempio sopra c'è una condizione di gara. È possibile per " / * child stuff * / " per finire prima di " / * parent stuff * / " inizia il che può comportare l'aggiunta del pid di un bambino all'elenco dei bambini dopo la sua uscita e la sua rimozione. Quando arriverà il momento in cui l'app si chiuderà, il genitore attenderà all'infinito il completamento del figlio già finito.

Una soluzione che mi viene in mente per contrastare questo è quella di avere due elenchi: start_children e finito_children . Aggiungerei a start_children nello stesso posto in cui sto aggiungendo children ora. Ma nel gestore del segnale, invece di rimuovere da children avrei aggiunto a finito_children . Quando l'app viene chiusa, il genitore può semplicemente attendere fino a quando la differenza tra start_children e finito_children è zero.

Un'altra possibile soluzione che mi viene in mente è l'utilizzo della memoria condivisa, ad es. condividere l'elenco dei figli dei genitori e lasciare che i bambini .add e .remove stessi? Ma non ne so molto di questo.

EDIT: Un'altra possibile soluzione, che è stata la prima cosa che mi è venuta in mente, è semplicemente aggiungere un sleep (1) all'inizio di / * child stuff * / ma questo ha un odore strano per me, motivo per cui l'ho lasciato fuori. Non sono nemmeno sicuro che sia una soluzione al 100%.

Quindi, come correggeresti questa condizione di gara? E se esiste un modello raccomandato consolidato, per favore fatemi sapere!

Grazie.

È stato utile?

Soluzione

La soluzione più semplice sarebbe quella di bloccare il segnale SIGCHLD prima di fork () con sigprocmask () e sbloccarlo nel codice genitore dopo aver elaborato il pid.

Se il bambino è morto, il gestore del segnale per SIGCHLD verrà chiamato dopo aver sbloccato il segnale. È un concetto di sezione critica: nel tuo caso la sezione critica inizia prima di fork () e termina dopo children.add () .

Altri suggerimenti

Se non puoi usare un frammento critico, forse un semplice contatore può fare questo lavoro. +1 quando aggiungi, -1 quando rimuovi, non importa quale succede prima, alla fine puoi ottenere zero quando tutto è finito.

Oltre all'esistente "figlio" aggiungere una nuova struttura di dati "morti precoci". Ciò manterrà pulito il contenuto dei bambini.

  // main program excerpt
    for (;;) {
      if ( is_time_to_make_babies ) {

        pid = fork();
        if (pid == -1) {
          /* fail */
        } else if (pid == 0) {
          /* child stuff */
          print "child started"
          exit
        } else {
          /* parent stuff */
          print "parent forked new child ", pid
          if (!earlyDeaths.contains(pid)) {
              children.add(pid);
          } else {
              earlyDeaths.remove(pid);
          }
        }

      }
    }

  // SIGCHLD handler
  sigchld_handler(signo) {
    while ( (pid = wait(status, WNOHANG)) > 0 ) {
      print "parent caught SIGCHLD from ", pid
      if (children.contains(pid)) {
          children.remove(pid);
      } else {
          earlyDeaths.add(pid);
      }
    }
  }

EDIT: questo può essere semplificato se il processo è a thread singolo - earlyDeaths non deve essere un contenitore, deve solo contenere un pid.

Forse un algoritmo ottimista? Prova children.remove (pid) e, se fallisce, vai avanti con la vita.

O controlla che pid sia presente nei bambini prima di provare a rimuoverlo?

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