Frage

Bitte beachten Sie die folgenden fork() / SIGCHLD Pseudo-Code.

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

Im obigen Beispiel gibt es ein Rennen-Zustand. Es ist möglich, für „/* child stuff */“ vor „/* parent stuff */“ beginnt zu beenden, die in einem Kind pid wird in der Liste der Kinder zur Folge haben können, nachdem er ausgetreten ist, und nie entfernt werden. Wenn die Zeit für die App kommt zu schließen, wird die Mutter endlos warten, bis das bereits fertiggestellte Kind zu beenden.

Eine Lösung, die ich denken kann, um dem entgegenzuwirken ist zwei Listen haben: started_children und finished_children. Ich würde hinzufügen, an der gleichen Stelle started_children Ich bin jetzt zu children hinzufügen. Aber in den Signal-Handler anstelle von children Entfernen Ich würde in finished_children. Wenn der App schliesst, können die Eltern einfach warten, bis der Unterschied zwischen started_children und finished_children Null ist.

Eine andere mögliche Lösung kann ich mir vorstellen ist mit gemeinsam genutztem Speicher, z.B. teilen sich die Liste der Eltern von Kindern und lassen Sie die Kinder .add und .remove selbst? Aber ich weiß nicht, zu viel darüber nach.

EDIT: Eine andere mögliche Lösung, die das erste, was war in den Sinn kam, ist einfach eine sleep(1) zu Beginn der /* child stuff */ hinzufügen, aber das riecht komisch für mich, weshalb ich es weggelassen. Ich bin auch nicht sicher, es ist ein 100% fix.

So, wie würden Sie korrigieren dieses Rennen-Zustand? Und wenn es ein gut etabliertes empfohlenen Muster für diese, lassen Sie es mich wissen!

Danke.

War es hilfreich?

Lösung

Einfachste Lösung wäre SIGCHLD Signal vor fork() mit sigprocmask() zu blockieren und es in übergeordnetem Code zu entsperren, nachdem Sie die pid bearbeitet haben.

Wenn das Kind starb, Signal-Handler für SIGCHLD wird aufgerufen, nachdem Sie das Signal zu entsperren. Es ist ein kritischer Abschnitt Konzept -. In Ihrem Fall kritische Abschnitt beginnt, bevor fork() und endet nach children.add()

Andere Tipps

Wenn Sie nicht kritisches Fragment verwenden kann, vielleicht ein einfacher Zähler kann diesen Job machen. +1, wenn add, -1, wenn entfernen, kein mater, die man zuerst passieren, man kann schließlich Null erhalten, wenn alles getan ist.

Zusätzlich zu den bestehenden „Kindern“ fügen Sie eine neue Datenstruktur „frühe Todesfälle“. Dies hält den Inhalt der Kinder sauber.

  // 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:. Dies vereinfacht werden kann, wenn der Prozess Single-Threaded ist - earlyDeaths nicht über einen Behälter sein, es hat nur ein pid halten

Vielleicht ein optimistischer Algorithmus? Versuchen children.remove (pid), und wenn es fehlschlägt, fahren Sie mit dem Leben.

oder prüfen, ob pid bei Kindern ist, bevor Sie versuchen, es zu entfernen?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top