Wir haben ein altes Projekt, das wir unterstützen, und es gibt ein Problem, das höchstwahrscheinlich auf Multithreading zurückzuführen ist.
Der ursprüngliche Implementierer hat ihn "repariert", indem er eine Thread.sleep
vor dem Ausführen des problematischen Abschnitts ausgeführt hat.
Die Problemumgehung funktioniert, aber da sich der Abschnitt innerhalb einer Schleife befindet, fügt thread.sleep
mehrere Minuten zu der Zeit hinzu, die für die Fertigstellung des Abschnitts benötigt wird.
Im letzten Monat haben wir mit niedrigeren Werten für den Schlaf experimentiert, aber wir möchten die Ursache herausfinden. Während unserer Untersuchungen machten wir lock
auf privaten Objekten, wo immer wir uns fühlten.
Wir suchten nach allem, was zusätzliche Threads hervorbringen könnte - fand keine.
Kein Thread.start und keine Verwendung von ThreadPool.
Was uns verwirrt, ist, dass wir während des Debuggens unseren Hauptthread in der Mitte von ungefähr 8 anderen Threads finden, von denen wir nicht wissen, wer sie erzeugt hat.
Dies sind Hintergrund-Threads, so dachte ich zuerst, war der Threadpool, aber wie ich erwähnte, erwähnt es nicht im Code.
Es ist .net 2.0 also kein Async
s.
Dies ist nur ein Teil der größeren Anwendung, also ist es ein Windows-Dienst, aber wir führen es als CMD aus, um es leicht debuggen zu können. Die Hauptanwendung selbst ist eine Windows Forms-Desktop-App.
Es verwendet auch COM + -Komponenten, wenn das Hilfe ist.
Ich habe [STA]
anstelle von [MTA]
ausprobiert.
Auch wie oben erwähnt sperren.
MemoryBarrier
s ebenfalls.
Wir bekommen immer noch das Problem.
Das Problem besteht im Wesentlichen in beschädigten Datasets und Nullen in Objekten, wo sie nicht sein sollten. Es passiert in etwa einmal alle 25-100 Iterationen, so dass die Reproduktion nicht direkt ist, aber wir haben einen Test speziell für dieses Problem entwickelt, um zu versuchen, es zu reproduzieren.
All das weist uns in die Richtung von Threadproblemen.
Zurück zur ursprünglichen Frage - Wer könnte diese zusätzlichen Threads erzeugen und wie verhindern wir, dass diese Threads erstellt werden?
Bitte beachten Sie die rot markierten Threads - das sind Hintergrundthreads und soweit wir sie nicht im Code sehen können.
Der vermutete Thread im Screenshot verändert aktiv die Spalten in dataset
. Problem ist - die Methoden, die die Funktion SetColValueOnRow
aufrufen, die der Thread ausführt, sind typisch und verwenden keine Art von Threading.
Die CPU-Affinität für diese Anwendung ist auf 1 Kern [Teil des ursprünglichen Workarounds] festgelegt.
Danke
Bearbeiten: Die Datenbank ist Oracle 12c, aber die Probleme, vor denen wir stehen, passieren vor dem Schreiben in die Datenbank. Sie treten normalerweise in DataSets auf, wo ein ganzer Datensatz oder einige seiner Spalten nach jeweils wenigen Testzyklen gelöscht werden können.
Ich denke, Sie müssen herausfinden, warum Thread.sleep funktioniert. Es klingt nicht so, als würde der Code selbst weitere Threads erzeugen, aber Sie müssten die gesamte Codebasis durchsuchen, um das herauszufinden - einschließlich der COM + -Komponenten.
Das erste, was ich tun würde, ist, das Programm im Debug zu starten und einfach die Taste F10 zu drücken, um in das Programm zu gelangen. Öffnen Sie dann das Thread-Debug-Fenster und sehen Sie, ob Sie ungefähr die gleiche Anzahl von Threads sehen, wie in Ihrer Frage angegeben. Wenn Sie das tun, sind das nur Threads aus dem Thread-Pool, und Ihr Problem ist wahrscheinlich nicht mit den mehreren Threads verbunden.
Wenn Sie nicht die gleiche Anzahl von Threads sehen, versuchen Sie, einen Haltepunkt in verschiedenen Phasen des Programms zu setzen, und sehen Sie, ob Sie herausfinden können, wo diese Threads erstellt werden. Wenn Sie feststellen, wo sie erstellt werden, können Sie versuchen, an dieser Stelle eine Sperre hinzuzufügen. Ihr Problem wird jedoch möglicherweise nicht durch mehrere beschädigte Threads verursacht. Sie sollten untersuchen, bis Sie überzeugt sind, dass das Problem auf mehrere Threads oder etwas anderes zurückzuführen ist.
Ich vermute, dass das Problem mit einer oder mehreren der COM + -Komponenten zusammenhängen könnte oder dass der Code eine lang laufende gespeicherte Datenbankprozedur aufruft. In jedem Fall vermute ich, dass Thread.sleep funktioniert, weil es der fehlerverdächtigen Komponente genug Zeit gibt, um ihre Operation abzuschließen, bevor sie mit der nächsten Operation beginnt.
Wenn diese Theorie zutrifft, deutet dies darauf hin, dass es eine Interaktion zwischen den Operationen gibt und wenn Thread.Sleep einen ausreichend großen Wert erhält, damit der Vorgang abgeschlossen werden kann - es gibt keine Interaktionsprobleme. Dies deutet auch darauf hin, dass möglicherweise eine der COM + -Komponenten einige Dinge asynchron ausführt. Die Lösung besteht möglicherweise darin, Sperren oder kritische Abschnitte innerhalb des COM + -Komponentencodes zu verwenden. Eine andere Idee besteht darin, den Codeabschnitt neu zu entwerfen, der das gleichzeitige Ausführen mehrerer Vorgänge ermöglicht.
Das Problem, auf das Sie stoßen, liegt möglicherweise nicht an mehreren Threads im C # -Code, die Sie betrachten, sondern an einer lang andauernden Operation, die manchmal fehlschlägt, wenn nicht genügend Zeit für den Abschluss des Vorgangs vorhanden ist nächste Operation. Dies kann auf mehrere Threads im C # -Code zurückzuführen sein oder nicht.
Tags und Links c# multithreading desktop-application com+