2009-08-05 9 views
19

Ich habe gehört, dass das Mischen von Forking und Threading in einem Programm sehr problematisch sein könnte, oft mit mysteriösen Verhalten, insbesondere im Umgang mit freigegebenen Ressourcen, wie Sperren, Pipes, Dateideskriptoren. Aber ich verstehe nie genau, was genau die Gefahren sind und wann diese passieren können. Es wäre großartig, wenn jemand mit Fachkenntnissen in diesem Bereich ein bisschen mehr im Detail erklären könnte, welche Fallstricke es gibt und was bei der Programmierung in einer solchen Umgebung zu beachten ist.Fork in Multi-Thread-Programm

Zum Beispiel, wenn ich einen Server schreiben möchte, der Daten von verschiedenen Ressourcen sammelt, eine Lösung, die ich dachte, ist der Server spawns eine Reihe von Threads, jeder Popen ein anderes Programm aufrufen, um das eigentliche zu tun arbeiten, offene Leitungen öffnen, um die Daten vom Kind zurück zu bekommen. Jeder dieser Threads antwortet auf seine eigene Arbeit, kein Datenaustausch in s/w, und wenn die Daten gesammelt werden, hat der Haupt-Thread eine Warteschlange und diese Worker-Threads werden das Ergebnis einfach in die Warteschlange stellen. Was könnte mit dieser Lösung schiefgehen?

Bitte schränken Sie Ihre Antwort nicht ein, indem Sie einfach mein Beispielszenario "beantworten". Irgendwelche Vorschläge, alternative Lösungen oder Erfahrungen, die nicht mit dem Beispiel verbunden sind, aber hilfreich sind, um ein sauberes Design zur Verfügung zu stellen, wären großartig! Vielen Dank!

+0

hier ist ein [gut lesen] (http://thorstenball.com/blog/2014/10/13/why-threads-cant-fork/) mit mehr Details zum Thema - –

Antwort

0

Es ist wirklich ziemlich einfach. Die Probleme mit mehreren Threads und Prozessen ergeben sich immer aus gemeinsamen Daten. Wenn keine gemeinsamen Daten vorhanden sind, können keine Probleme auftreten.

In Ihrem Beispiel sind die freigegebenen Daten die Warteschlange, die dem Hauptthread gehört - es entstehen hier mögliche Konflikte oder Race Conditions. Typische Methoden zum "Lösen" dieser Probleme sind Sperrschemata - ein Worker-Thread sperrt die Warteschlange vor dem Einfügen von Daten, und der Haupt-Thread sperrt die Warteschlange, bevor sie entfernt wird.

+0

zählt die Malloc-Metadaten als "geteilte Daten"? :) – bdonlan

+0

Ich weiß nicht - es könnte aber normalerweise Ihre Standard-Bibliotheken sind so geschrieben, dass thread sicher (manchmal müssen Sie thread-sichere Versionen von ihnen wählen). Es hängt davon ab, was Ihre Definition von gemeinsamen Daten ist und was die Auswirkung ist. –

+0

oft können wir nicht vermeiden, Daten geteilt zu haben. wie Pipes, Dateideskriptoren usw. Sie werden immer über die Gabel verteilt. Unter Linux kann man das Flag O_CLOEXEC setzen, so dass ein fd beim Forking geschlossen werden kann (ich denke, das ist die fd im Adreßraum des Kindes), obwohl ich nicht weiß, ob das helfen würde, wenn wir Threads hinzufügen ? z.B. Was passiert, wenn ich Rohre in einem Gewinde öffne und abzweige? Was ist, wenn ein anderer Thread auch eine Gabelung ausführt? Welches Kind wird die Pfeife sehen können? – jimx

16

Das Problem mit Forking, wenn Sie einige Threads ausführen, ist, dass die Gabel nur den CPU-Status des einen Thread kopiert, der es aufgerufen hat. Es ist, als wären alle anderen Threads sofort gestorben, egal wo sie sind.

Das Ergebnis davon ist, dass Sperren nicht freigegeben werden und freigegebene Daten (wie der Malloc-Heap) möglicherweise beschädigt sind.

Pthread bietet zwar eine pthread_atfork Funktion - in der Theorie, Sie jedes Schloss in dem Programm nehmen konnte, bevor gabeln, geben sie nach und vielleicht es lebendig machen - aber es ist riskant, weil man immer eine verpassen könnte. Und natürlich werden die Stapel der anderen Threads nicht freigegeben.

+0

Können Sie ein wenig ausarbeiten, was es heißt, "Schlösser sind nicht freigegeben"? Aus der Kinderperspektive, oder? Also kann das Kind niemals ein Schloss bekommen? – jimx

+0

Korrigieren. Die Verzweigung klont alle Sperren, während sie sich noch im gesperrten Zustand befinden. – bdonlan