Wie debugge ich einen einzelnen Thread in Visual Studio?

254

Ich habe eine Lösung mit einigen Projekten. In verschiedenen Projekten gibt es mehrere Haltepunkte. Ich möchte verfolgen, ob der erste Thread einen dieser Haltepunkte erreicht hat, und diesen einzelnen Thread weiter verfolgen, obwohl andere Threads dieselben Codeblöcke eingeben.

Ich weiß, dass dies möglich ist, indem eine Bedingung am Haltepunkt definiert wird, dh Threadname = ... oder Thread-ID = ..., aber mein Fall ist eine stark geladene ASP.NET- Anwendung und sobald ich an w3wp.exeviele anhänge Threads treffen die Haltepunkte. Ich brauche so etwas wie ein ThreadLocal<break-point>.

Ist es möglich? Wenn das so ist, wie?

Xaqron
quelle
7
@Paolo: Diese Webanwendung fungiert als Herzstück einer großen Webfarm, und die Fehlersituation kann in Testszenarien nicht nachgeahmt werden.
Xaqron
Für VS 2019 sollten Sie dies möglicherweise versuchen: stackoverflow.com/a/61868591/8579563
Gozo

Antworten:

150

Das Einfrieren / Auftauen von Threads ist eine falsche Methode, da andere Threads keinen Code ausführen.

Der korrekteste und nützlichste Weg ist:

  1. Drücken Sie im Haltepunktfenster Strg + A (wählen Sie alle Haltepunkte aus).
  2. Klicken Sie mit der rechten Maustaste und wählen Sie "Filter ...".
  3. Geben Sie "ThreadId = (aktuelle Thread-ID)" ein.

In Visual Studio 2015 und höher ist der Prozess ähnlich:

  1. Drücken Sie im Haltepunktfenster Strg + A (wählen Sie alle Haltepunkte aus).
  2. Klicken Sie mit der rechten Maustaste und wählen Sie "Einstellungen ...".
  3. Aktivieren Sie "Bedingungen" und wählen Sie "Filter" in der Dropdown-Liste
  4. Geben Sie "ThreadId = (aktuelle Thread-ID)" ein.

Es werden also alle Threads ausgeführt, aber der Debugger trifft nur auf den aktuellen Thread.

hzdbyte
quelle
51
Verhindert dies, dass der Debugger-Befehl "Step" andere Threads eingibt? Das war ein großes Problem, das ich hatte. Ich gehe meinen Thread durch und bin plötzlich in einem völlig unabhängigen Teil des Codes. Ich entwickle nicht mehr in Visual Studio, daher kann ich nicht testen.
Matt Faus
8
Ein Rechtsklick in das Haltepunktfenster hat keinen "Filter" -Befehl ... und wie finden Sie die aktuelle Thread-ID überhaupt heraus? - Gehst du zum unmittelbaren Fenster und tippst System.Threading.Thread.CurrentThread.ManagedThreadIdoder so?
BrainSlugs83
5
In meinem VS (2015, Community Edition) ist es nicht möglich, die Einstellungen mehrerer Haltepunkte gleichzeitig zu ändern. Somit kann der Filter nur einzeln eingestellt werden.
Robert4
5
Ich hatte dieses Problem schon immer und ich könnte schwören, dass ich bei meinem letzten Job eine Einstellung gefunden habe, mit der Visual Studio wie Eclipse funktioniert, bei der Sie sich an den Thread halten, mit dem Sie gearbeitet haben, aber ich kann ihn oder eine Referenz nicht finden dazu. Ich fange an mich zu fragen, ob ich davon geträumt habe.
stu
7
-1, da dies nur Haltepunkte zulässt, aber nicht tatsächlich debuggt: step over / step into funktioniert beim Debuggen eines einzelnen Threads nicht auf diese Weise.
Serge Rogatch
338

Folgendes habe ich getan:

  1. Stellen Sie einen bedingten Haltepunkt ein, von dem ich wusste, dass er nur auf den gesuchten Thread trifft.

  2. Sobald der Haltepunkt erreicht ist und Sie sich im gewünschten Thread befinden, klicken Sie im Fenster Visual Studio-Threads (während des Debuggens auf Debuggen -> Windows -> Threads) auf Ctrl+ A(um alle Threads auszuwählen) und dann Ctrlauf den Thread, in dem Sie sich gerade befinden . Sie sollten alle Threads außer dem auswählen, den Sie debuggen möchten.

  3. Klicken Sie mit der rechten Maustaste und wählen Sie "Einfrieren".

Jetzt durchläuft Visual Studio nur noch den aufgetauten Thread. Es scheint dabei viel langsamer zu sein, vermutlich weil es alle eingefrorenen Threads durchlaufen muss, aber es hat meinem Multithread-Debugging etwas Vernunft gebracht.

Matt Faus
quelle
1
Dies funktioniert bei mir nicht in einem Kontext, in dem ungefähr 8 Aufgaben in verschiedenen Threads ausgeführt werden. Ich friere alle anderen Threads ein und "gehe über", aber die IDE friert für eine Weile ein und springt dann trotzdem zu einem anderen Thread.
Meta-Knight
3
@Diego: Ich arbeite nicht mehr an dem Projekt, aber wenn alle Threads außer einem eingefroren werden, ändert sich das Szenario, das den Fehler verursacht hat, da sich die Threads in einer fehlerhaften Situation ergänzten. Obwohl dies eine elegante Lösung ist, sollte diese Funktion in VS eingebettet werden.
Xaqron
3
@ Meta-Knight Du solltest alle Threads außer dem Haupt-Thread einfrieren . Wenn Sie diese IDE mögen, wird sie nicht eingefroren
Alex Zhukovskiy
15

Ich habe gerade eine Visual Studio 2010+ -Erweiterung veröffentlicht, die genau das tut, wonach Sie suchen. Und es ist kostenlos :).

Präsentation

Diese Visual Studio-Erweiterung enthält zwei Verknüpfungen und Symbolleistenschaltflächen, mit denen Entwickler sich beim Debuggen von Multithread-Anwendungen problemlos auf einzelne Threads konzentrieren können.

Es reduziert die Notwendigkeit, manuell in das Threads-Fenster zu gehen, um alle Threads einzufrieren / aufzutauen, außer dem, der befolgt werden muss, drastisch und trägt daher zur Verbesserung der Produktivität bei.

Eigenschaften

Beschränken Sie die weitere Ausführung nur auf den aktuellen Thread. Friert alle anderen Threads ein. Tastenkürzel: STRG + T + T oder Schneeflockentaste. Wechseln Sie zum nächsten einzelnen Thread (basierend auf der ID). Ändert den aktuellen Thread und friert alle anderen Threads ein. Tastenkürzel: STRG + T + J oder Weiter.

Überprüfen Sie es hier in der Galerie , auf der offiziellen Seite oder im Github-Repository .

Erwin Mayer
quelle
Welche VS-Version verwenden Sie?
Erwin Mayer
Ich habe die Erweiterung installiert, aber nicht zum Laufen gebracht (für mein aktuelles Projekt verwende ich VS2010). [Übrigens, was ich für ein Problem mit der Aktivierung von Threads hielt, passiert nur, wenn Threads erstellt werden. Dies ist wahrscheinlich ein Standardverhalten, daher habe ich meinen vorherigen Kommentar entfernt.]
Wischen Sie den
3
Ich werde das überprüfen. Sie sind möglicherweise die einzige Person auf dem Planeten, die versucht hat, einen der größten Fehler beim Debuggen von Microsoft zu beheben.
stu
Leider wird es nicht auf vs2012 installiert. Haben Sie eine neuere Version oder möchten Sie den Quellcode freigeben, damit ich ihn selbst erstellen kann?
stu
@stu Der Quellcode befindet sich hier auf Codeplex: singlethread.codeplex.com sollte auf VS 2012 und VS 2013 funktionieren, aber ich habe ihn nicht aktualisiert (niemand hat ihn angefordert und ich hatte selbst keine Notwendigkeit). Wenn Sie es mit VS 2012+ problemlos machen und Codeplex festlegen können, kann ich es auch in der Galerie veröffentlichen.
Erwin Mayer
13

Wenn wie bei einer Webanwendung mehrere Threads erzeugt werden, funktionieren die Antworten von @MattFaus nicht. Was ich stattdessen getan habe, ist das Folgende

  • Richten Sie einen Haltepunkt ein, um den Thread in der gewünschten Funktion zu unterbrechen.
  • Sobald der Thread den Haltepunkt erreicht und angehalten hat, entferne ich den Haltepunkt und setze das Debuggen mit F8, F10 und F11 fort, damit die anderen Threads ausgeführt werden können.
Mikaël Mayer
quelle
Nachdem ich alle Top-Antworten gelesen hatte, funktionierte diese Problemumgehung für mich.
Swanand Pangam
9

Ein etwas anderer Ansatz, den ich verwendet habe:

  1. Erstellen Sie einen normalen Haltepunkt und lassen Sie ihn treffen
  2. Suchen Sie in Ihrem Thread-Fenster nach der verwalteten Thread-ID, die Sie gerade debuggen
  3. Klicken Sie mit der rechten Maustaste auf Ihren Haltepunkt im Fenster Haltepunkte und Auswahlfilter
  4. Geben Sie ThreadId = xxx ein, wobei xxx die Thread-ID von 2 ist
  5. Sie können jetzt debuggen, ohne andere Threads anzuhalten und ohne dass sie Ihren Haltepunkt erreichen

Dies setzt voraus, dass Sie Zeit haben, die oben genannten Schritte auszuführen, bevor ein zweiter Thread Ihren Haltepunkt erreicht. Wenn dies nicht der Fall ist und andere Threads Ihren Haltepunkt erreichen, bevor Sie die oben genannten Schritte ausgeführt haben, können Sie mit der rechten Maustaste auf sie im Thread-Fenster klicken und Einfrieren auswählen.

Matt
quelle
3
+1. "Dies setzt voraus, dass Sie Zeit haben ... bevor ein zweiter Thread Ihren Haltepunkt erreicht". Ich wickle ein Semikolon in ein Schloss und setze einen Haltepunkt auf das Semikolon. Wenn der Haltepunkt zum ersten Mal erreicht wird, deaktiviere ich den Haltepunkt. Aufgrund der Sperre können keine anderen Gewinde eingehen. lock(m_someObject) { ; }
Bluedog
Um Ihnen ein Google zu speichern, finden Sie das Thread-Fenster unter Debug> Windows> Threads.
Gabe
2

In VS 2019:

  1. Setzen Sie irgendwo einen Haltepunkt.
  2. Drücke F5 (Weiter), bis dein Thread kommt.
  3. Klicken Sie auf den Haltepunkt, um ihn zu entfernen.
  4. Sie können den Thread mit F10 oder F11 schrittweise ausführen.
Gozo
quelle
Funktioniert auch für VS2015!
prähistorisches
1

Ich würde vorschlagen, eine weitere Instanz der Anwendung auf dem Live-Server hinzuzufügen, entweder auf derselben Hardware oder auf einem neuen Computer (Cluster it) und dann nur diese Instanz zu debuggen. Ich würde keinen Haltepunkt in Code hinzufügen, den Benutzer auslösen. Wenn dies keine Option ist, würde ich mehr Ablaufverfolgung hinzufügen.

Wenn dies jedoch unbedingt erforderlich ist und Sie einen Lösungsstatus benötigen, können Sie sicher einen Haltepunkt hinzufügen, der nur dann unterbrochen wird, wenn die Anforderung von Ihrer IP-Adresse stammt. Sie würden dies tun, indem Sie einen bedingten Haltepunkt hinzufügen, der überprüft HttpContext.Request.UserHostAddress. Beachten Sie jedoch, dass dies Ihre Anwendung erheblich verlangsamt.

Steinar
quelle
Das habe ich versucht. Das Problem ist, dass diese Instanz nicht in derselben Domäne arbeitet (unter IP oder einer anderen Domäne) und dies zu vielen Zertifikatsproblemen (SSL, WCF, ...) führt. Auch bei geringer Last tritt die fehlerhafte Situation nie auf!
Xaqron
Entschuldigung, ich bin mir nicht sicher, welche davon Sie ausprobiert haben. Haben Sie den bedingten Haltepunkt ausprobiert?
Steinar
Ja, ich habe sie basierend auf ihrer verwalteten ID benannt, um die Eindeutigkeit sicherzustellen. Dann ist es schwer zu erraten, welche ID zugewiesen ist, und die Bedingung basierend auf einer Vermutung festzulegen. Manchmal ist die Vermutung nah und manchmal dauert es lange, bis der Faden aufgefangen ist.
Xaqron
1

Wenn Sie nicht alle anderen Threads stoppen möchten (möglicherweise hängen Sie den Visual Studio-Debugger an eine laufende Anwendung an, die auf Anforderungen antworten muss), können Sie ein Makro verwenden, mit dem Haltepunkte automatisch erstellt und entfernt werden.

Dies wird in einer Antwort auf die Stapelüberlauffrage "Step over" beim Debuggen von Multithread-Programmen in Visual Studio vorgeschlagen .

Der Link erklärt jedoch nur das zeilenweise Debuggen. Ich schlage vor, dass Sie das Makro ändern (wenn Sie damit vertraut sind), damit alle Haltepunkte (z. B. in einem bestimmten Zeilenbereich) so geändert werden, dass sie nur im aktuellen Thread anhalten.

Kamaradclimber
quelle
1

Ich denke, dass dies in Visual Studio 2015 etwas anders ist. Sie haben einige Änderungen an den Haltepunkten vorgenommen, aber hier erfahren Sie, wie Sie die akzeptierte Antwort von hzdbyte (oben) anwenden:

Klicken Sie am Haltepunkt am Codierungsrand mit der rechten Maustaste auf> Bedingungen> Von 'Bedingter Ausdruck' zu 'Filter'. Auf diese Weise können Sie nach ThreadId filtern.

Alternativ können Sie auf dem Haltepunkt im Fenster Haltepunkte mit der rechten Maustaste> Einstellungen> das Kontrollkästchen Bedingungen aktivieren und die oben genannten Schritte ausführen.

Patelos
quelle
1

Legen Sie eine Haltepunktbedingung fest, indem Sie mit der rechten Maustaste auf die Seitenleiste der Linie klicken. Wählen Sie "Bedingung" und geben Sie Folgendes mit dem Namen Ihres Threads in Anführungszeichen ein:

System.Threading.Thread.CurrentThread.Name == "name_of_your_thread"

Alternativ können Sie dasselbe tun, indem Sie die "verwaltete ID" des Threads aus dem Fenster "Threads" abrufen und Folgendes verwenden:

System.Threading.Thread.CurrentThread.ManagedThreadId == your_managed_thread_id

James Sheridan
quelle