Gibt es Zombies? In .NET?
Ich hatte eine Diskussion mit einem Mitspieler zu sperren .NET. Er ist ein wirklich kluger Kerl mit einem umfangreichen hintergrund in beiden lower-level und High-level-Programmierung, aber seine Erfahrungen mit niedrigeren level-Programmierung weit über mir. Wie auch immer, Er argumentiert, dass .NET sperren sollten vermieden werden, auf kritische Systeme, erwartet, dass unter starker Auslastung, wenn überhaupt möglich, um zu vermeiden, dass die-zugegebenermaßen geringe-Möglichkeit einer "zombie-thread" Absturz eines Systems. Ich routinemäßig verwenden, sperren und wusste ich nicht, was ein "zombie-thread" war, also fragte ich. Ich bekam den Eindruck von seiner Erklärung ist, dass ein zombie-thread ist ein thread, der beendet wurde, aber irgendwie immer noch hält Sie auf einige Ressourcen. Ein Beispiel gab er, wie ein zombie-thread könnte brechen ein system war ein thread beginnt einige Verfahren nach dem sperren auf ein Objekt, und dann ist irgendwann beendet, bevor die Sperre freigegeben werden kann. Diese situation hat das Potenzial zu einem Absturz des Systems, denn schließlich, versucht, die execute-Methode wird das Ergebnis in die alle threads, die darauf warten für den Zugriff auf ein Objekt, wird nie zurückgegeben werden, weil der thread, der den gesperrten Objekt tot ist.
Ich denke ich habe den Kern dieses, aber wenn ich bin off base, lassen Sie es mich bitte wissen. Das Konzept machte Sinn für mich. Ich war nicht völlig überzeugt, dass dies ein realistisches Szenario, was passieren könnte .NET. Ich habe noch nie zuvor gehört "zombies", aber ich erkenne, dass die Programmierer gearbeitet haben, in Tiefe, in den unteren Ebenen haben tendenziell ein tieferes Verständnis der computing-Grundlagen (wie threading). Ich auf jeden Fall tun, sehen den Wert zu sperren, aber, und ich habe gesehen, viele Weltklasse-Programmierer Hebel sperren. Ich habe auch nur eingeschränkte Möglichkeiten, um das zu beurteilen für mich, weil ich weiß, dass die lock(obj)
- Anweisung ist eigentlich nur syntaktischer Zucker für:
bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }
und weil Monitor.Enter
und Monitor.Exit
gekennzeichnet sind extern
. Es scheint denkbar, dass .NET hat einige Art der Verarbeitung, schützt das Gewinde vor der Exposition gegenüber Systemkomponenten, hätte diese Art von Einfluss, aber das ist rein spekulativ und wohl nur auf der Tatsache beruht, dass habe ich noch nie gehört "zombie-threads" vor. So, ich hoffe ich bekomme etwas feedback dazu hier:
- Gibt es eine klarere definition von "zombie-thread" als das, was ich erklärt habe hier?
- Können zombie-threads treten auf .NET? (Warum/warum nicht?)
- Wenn ja, Wie könnte ich die Kraft, die Schaffung eines zombie-thread .NET?
- Wenn ja, Wie kann ich den Hebel verriegeln, ohne zu riskieren einen zombie-thread-Szenario .NET?
Update
Fragte ich diese Frage ein wenig vor über zwei Jahren. Heute passiert:
InformationsquelleAutor der Frage smartcaveman | 2013-11-19
Du musst angemeldet sein, um einen Kommentar abzugeben.
Scheint wie eine ziemlich gute Erklärung für mich - ein thread, der beendet wurde (und somit nicht mehr freigeben Ressourcen), aber deren Ressourcen (z.B. Griffe) sind immer noch rund und (potenziell) Probleme verursacht.
Klar, dass Sie tun, sehen Sie, ich aus!
Dieses Programm startet einen thread
Target
welches eine Datei öffnet und dann sofort tötet, selbst mitExitThread
.Die entstehende zombie-thread wird nie lassen Sie den Griff, um die "test.txt die" Datei-und damit die Datei geöffnet bleibt, bis das Programm beendet wird (Sie können check mit dem process explorer oder ähnliche).Den Griff "test.txt" wird nicht freigegeben, bisGC.Collect
genannt wird - es stellt sich heraus, es ist noch schwieriger, als ich dachte, zum erstellen einer zombie-thread, dass Leckagen Griffe)Nicht tun, was ich gerade getan habe!
Solange Ihr code bereinigt nach sich selbst korrekt (verwenden Sie Sichere Griffe oder entsprechenden Klassen bei der Arbeit mit nicht verwalteten Ressourcen), und solange Sie don ' T gehen aus dem Weg, um zu töten threads in seltsame und wunderbare Möglichkeiten (der sicherste Weg ist, nur um nie mehr zu töten threads - lassen Sie Sie kündigen sich, normalerweise, oder durch Ausnahmen, wenn es nötig ist), der einzige Weg, dass Sie gehen, um etwas, das aussieht wie ein zombie-thread ist, wenn etwas nicht sehr falsch (z.B. etwas schief geht in der CLR).
In der Tat ist es tatsächlich überraschend schwierig zu erstellen, ein zombie-thread (ich hatte zu P/Invoke-in eine Funktion, die esentially erzählt Sie in der Dokumentation nicht zu nennen, es außerhalb von C). Zum Beispiel die folgenden (schrecklich) code tatsächlich nicht schaffen, ein zombie-thread.
Trotz einige ziemlich schrecklichen Fehler, den Griff "test.txt" ist noch geschlossen, sobald
Abort
wird (als Teil der finalizer fürfile
die unter der Decke verwendet SafeFileHandle wickeln Ihre Datei-handle)Die Verriegelung Beispiel in C. Evenhuis Antwort ist wahrscheinlich der einfachste Weg, um nicht zu release eine Ressource (eine Sperre in diesem Fall), wenn ein thread beendet wird, die in einem nicht-seltsamen Art und Weise, aber das ist leicht behoben werden, indem entweder ein
lock
- Anweisung anstelle, oder setzen Sie das release in einemfinally
block.Siehe auch
codegen
für eine sehr subtilen Fall, wo eine Ausnahme kann verhindern, dass eine Sperre aus
veröffentlicht wird auch bei der Verwendung der
lock
Schlagwort (aber nur in .Net 3.5 und früher)mix
InformationsquelleAutor der Antwort Justin
Ich habe aufgeräumt, meine Antwort ein bisschen, aber Links das original unten für Referenz
Es ist das erste mal, ich habe gehört der Begriff zombies, so werde ich davon ausgehen, dass seine definition ist:
Ein thread, der beendet wurde, ohne alle seine Ressourcen
So gegeben, dass die definition, dann ja, Sie können tun, dass in .NET, als mit anderen Sprachen (C/C++, java).
Jedochich glaube nicht, dass dies als ein guter Grund, nicht zu schreiben, Gewinde -, mission-critical code .NET. Es können auch andere Gründe zu entscheiden, gegen .Aber NET abschreiben .NET nur, weil Sie können zombie-threads irgendwie nicht so Sinn für mich. Zombie-threads sind möglich, die in C/C++ (ich würde sogar behaupten, dass es einfacher ist, in Unordnung zu bringen, in C) und eine Menge von kritischen, threaded-Anwendungen werden in C/C++ (high-volume-trading, Datenbanken, etc).
Abschluss
Wenn Sie in den Prozess der Entscheidung, auf eine Sprache zu verwenden, dann schlage ich vor, Sie nehmen das Gesamtbild in Betracht: Leistungen, team, Kompetenzen, Zeitplan, integration mit bestehenden Anwendungen etc. Sicher, zombie-threads sind etwas, das Sie denken sollten, aber da es so schwer ist, tatsächlich diese Fehler machen .NET im Vergleich zu anderen Sprachen wie C, ich denke, diese Sorge überschattet werden durch andere Dinge wie die oben genannten. Viel Glück!
Ursprüngliche Antwort
Zombies† existieren können, wenn Sie nicht schreiben richtige threading-code. Das gleiche gilt für andere Sprachen wie C/C++ und Java. Aber das ist kein Grund, nicht zu schreiben threaded code .NET.
Und genau wie mit jeder anderen Sprache, kennen den Preis, bevor Sie so etwas. Es hilft auch zu wissen, was Los ist unter der Haube, so dass Sie absehen können mögliche Probleme.
Zuverlässigen code für unternehmenskritische Systeme ist nicht einfach zu schreiben, was auch immer Sprache, die Sie in. Aber ich bin sicher, es ist nicht unmöglich, das zu tun, korrekt .NET. Auch AFAIK .NET threading ist nicht so Verschieden von dem, threading in C/C++, verwendet es (oder integriert) die gleichen Systemaufrufe außer für einige .Netto-spezifische Konstrukte (wie die leichten Versionen von RWL und event-Klassen).
†zunächst mal, ich habe gehört der Begriff zombies, sondern auf der Grundlage Ihrer Beschreibung, Ihr Kollege meinte wohl ein thread, der beendet wurde, ohne alle Ressourcen freigeben. Dies könnte möglicherweise einen deadlock verursachen, Speicherverlust oder einige andere schlechte Nebenwirkungen. Dies ist natürlich nicht wünschenswert, aber die Hausnummer .NET, weil dieser Möglichkeit ist wahrscheinlich nicht eine gute Idee, da es möglich ist, auch in anderen Sprachen. Ich würde sogar argumentieren, dass es einfacher ist, um mess up in C/C++ als in .NET (besonders in C, wo Sie nicht RAII), aber viele wichtige apps sind geschrieben in C/C++ richtig? So dass es wirklich hängt von Ihren individuellen Umständen. Wenn Sie möchten, zu extrahieren, jedes Quäntchen an Geschwindigkeit aus Ihrer Anwendung und wollen so nah wie möglich an das blanke Metall wie möglich, dann .NET könnte nicht die beste Lösung. Wenn Sie auf einem festen Etat sind und tun eine Menge der Kommunikation mit web services/vorhandenen .net-Bibliotheken/etc dann .NET kann eine gute Wahl.
InformationsquelleAutor der Antwort Jerahmeel
Rechts jetzt sind die meisten meiner Antwort wurde korrigiert, indem die Kommentare unten. Ich werde Sie nicht löschen Sie die Antwort
da Brauch ich den Ruf Punkteweil die Informationen in den Kommentaren kann wertvoll sein, um Leser.Unsterblich Blau wies darauf hin, dass in .NET 2.0 und bis
finally
Blöcke sind immun gegen Faden bricht. Und wie kommentiert von Andreas Niedermair, dies kann nicht sein, eine tatsächliche zombie-thread, aber das folgende Beispiel zeigt, wie Sie den Abbruch der thread kann zu Problemen führen:Allerdings, wenn Sie eine
lock() { }
block, derfinally
würde noch ausgeführt werden, wenn einThreadAbortException
ausgelöst wird, Weg.Die folgenden Informationen, wie sich herausstellt, ist nur gültig für .NET 1 und .NET 1.1:
Wenn innerhalb der
lock() { }
block eine andere Ausnahme Auftritt, und dieThreadAbortException
kommt genau dann, wenn diefinally
block ist, werden ran, der lock wird nicht freigegeben. Wie Sie bereits erwähnt, dielock() { }
block zusammengefasst:Wenn ein anderer thread ruft
Thread.Abort()
innerhalb der generiertenfinally
sperren, die Sperre können nicht freigegeben werden.InformationsquelleAutor der Antwort C.Evenhuis
Dies ist nicht etwa die Zombie-threads, aber das Buch effective C# hat einen Abschnitt über die Implementierung von IDisposable, (item 17), was spricht über die Zombie-Objekte, die ich dachte, dass Sie interessant finden könnten.
Empfehle ich die Lektüre des Buches selbst, aber das wesentliche ist, dass wenn man eine Klasse IDisposable implementieren, oder mit einem Desctructor, die einzige Sache, die Sie tun sollten, entweder ist die Freigabe von Ressourcen. Wenn Sie andere Dinge zu tun hier, dann gibt es eine chance, dass das Objekt nicht werden, Müll gesammelt, sondern auch nicht erreichbar ist, in keiner Weise.
Gibt es ein Beispiel, ähnlich wie unten:
Wenn der Destruktor für dieses Objekt aufgerufen wird, eine Referenz auf sich selbst gestellt auf der globalen Liste, was bedeutet, es bleibt lebendig und im Speicher für die Lebensdauer des Programms, aber nicht zugänglich ist. Dies kann bedeuten, dass Ressourcen (vor allem nicht verwaltete Ressourcen) kann nicht vollständig freigesetzt, die bewirken, dass alle Arten von möglichen Problemen.
Ein ausführlicheres Beispiel finden Sie weiter unten. Durch die Zeit, die foreach-Schleife ist erreicht, Sie haben 150 Objekte in der Untoten-Liste mit jeweils einem Bild, aber das Bild hat schon GC würd und Sie erhalten eine Ausnahme, wenn Sie versuchen, es zu benutzen. In diesem Beispiel ist, erhalte ich eine ArgumentException (Parameter ist nicht gültig), wenn ich versuchen und etwas tun mit dem Bild, ob ich versuchen, es zu speichern, oder auch Abmessungen wie Höhe und Breite:
Wieder, ich bin bewusst, dass Sie gefragt wurden zombie-threads, insbesondere aber der Frage-Titel ist über zombies .net, und ich wurde daran erinnert und dachte, andere finden es vielleicht interessant!
InformationsquelleAutor der Antwort JMK
Auf kritische Systeme unter Last, schreiben lock-freien code ist besser, vor allem wegen der performance-Verbesserungen. Blick auf Sachen wie LMAX und wie man es nutzt "mechanical sympathy" für große Diskussionen. Sorgen über die zombie-threads, obwohl? Ich denke, das ist ein Grenzfall, das ist einfach ein bug ausgemerzt werden, und nicht ein guter genug Grund, es nicht zu verwenden
lock
.Klingt eher wie dein Freund ist einfach nur Phantasie und mit seinem wissen über obskure exotische Terminologie zu mir! In all der Zeit, die ich mit der performance labs bei Microsoft UK, ich kam nie über eine Instanz dieses Thema .NET.
InformationsquelleAutor der Antwort James World
Ich willige ein, dass die "Zombie-Threads" gibt, es ist ein Begriff, der zum verweisen auf das, was passiert mit Threads, die Links mit den Ressourcen, dass Sie nicht gehen zu lassen und noch nicht komplett sterben, daher der name "zombie", so Ihre Erklärung für diese Empfehlung ist ziemlich direkt auf das Geld!
Ja, Sie können auftreten. Es ist eine Referenz, und tatsächlich bezeichnet, die von Windows als "zombie": MSDN verwendet das Wort "Zombie" für Tot Prozesse/threads
Geschieht Häufig, es ist eine andere Geschichte und hängt davon ab, Ihre coding-Techniken und Praktiken, wie Sie für Sie, wie Thread Sperren und es für eine Weile ich würde nicht einmal darum kümmern, dass Szenario mit Ihnen geschieht.
Und ja, wie @KevinPanko richtig erwähnt in den Kommentaren, "Zombie-Threads" kommen aus der Unix-Welt, das ist, warum Sie verwendet werden, in der XCode-ObjectiveC und bezeichnet als "NSZombie" und für das Debuggen verwendet. Es verhält sich so ziemlich die gleiche Weise... der einzige Unterschied ist ein Objekt, das schon gestorben ist, wird ein "ZombieObject" für das Debuggen anstelle von "Zombie-Thread", das könnte ein mögliches problem im code.
InformationsquelleAutor der Antwort Steven Hernandez
Kann ich zombie-threads, die leicht genug.
Diese Lecks der thread-handles (für
Join()
). Es ist nur ein weiteres Speicher-Leck, so weit wir betroffen sind in der verwalteten Welt.Nun, töten einen thread in einer Weise, dass es tatsächlich sperren ist ein Schmerz in der Rückseite, aber möglich. Der andere Kerl
ExitThread()
macht den job. Als er gefunden wurde, die Datei-handle, habe aufgeräumt, die von der gc aber einelock
um ein Objekt würde nicht. Aber warum sollte man das tun?InformationsquelleAutor der Antwort Joshua