Jak debugować pojedynczy wątek w Visual Studio?

254

Mam rozwiązanie z niektórymi projektami. Istnieje kilka punktów krytycznych w różnych projektach. Chcę prześledzić pierwszy wątek trafiony w jeden z tych punktów przerwania i kontynuować śledzenie tego pojedynczego wątku, mimo że inne wątki wprowadzają te same bloki kodu.

Wiem, że jest to możliwe poprzez zdefiniowanie warunku w punkcie przerwania, to znaczy nazwa wątku = ... lub identyfikator wątku = ... ale moja sprawa jest mocno obciążoną aplikacją ASP.NET i jak tylko dołączę do w3wp.exewielu wątki uderzą w punkty przerwania. Potrzebuję czegoś takiego jak ThreadLocal<break-point>.

Czy to możliwe? Jeśli tak to jak?

Xaqron
źródło
7
@Paolo: Ta aplikacja internetowa działa jako serce dużej farmy internetowej, a błędnej sytuacji nie można naśladować w scenariuszach testowych.
Xaqron,
W przypadku VS 2019 może powinieneś spróbować: stackoverflow.com/a/61868591/8579563
Gozo

Odpowiedzi:

150

Wątki Freeze / Thaw to niepoprawny sposób, ponieważ inne wątki nie wykonują żadnego kodu.

Najbardziej poprawnym i użytecznym sposobem jest:

  1. Naciśnij Ctrl + A w oknie punktów przerwania (wybierz wszystkie punkty przerwania).
  2. Kliknij prawym przyciskiem myszy i wybierz „Filtruj ...”.
  3. Wpisz „ThreadId = (bieżący identyfikator wątku)”.

W programie Visual Studio 2015 i nowszych proces jest podobny:

  1. Naciśnij Ctrl + A w oknie punktów przerwania (wybierz wszystkie punkty przerwania).
  2. Kliknij prawym przyciskiem myszy i wybierz „Ustawienia ...”.
  3. Zaznacz „Warunki” i wybierz z menu „Filtruj”
  4. Wpisz „ThreadId = (bieżący identyfikator wątku)”.

Wszystkie wątki są wykonywane, ale debugger trafia tylko do bieżącego wątku.

hzdbyte
źródło
51
Czy to uniemożliwia komendie debugowania „Step” wejście do innych wątków? To był duży problem, który miałem. Przechodzę przez wątek i nagle jestem w całkowicie niezwiązanej części kodu. Nie rozwijam się już w Visual Studio, więc nie mogę testować.
Matt Faus
8
Kliknięcie prawym przyciskiem myszy w oknie punktów przerwania nie ma polecenia „filtruj” ... i jak możesz znaleźć bieżący identyfikator wątku? - Idziesz do bezpośredniego okna i piszesz System.Threading.Thread.CurrentThread.ManagedThreadIdczy coś?
BrainSlugs83
5
W moim VS (2015, wydanie wspólnotowe) nie jest możliwa modyfikacja ustawień wielu punktów przerwania jednocześnie. Dlatego filtr można ustawić tylko jeden po drugim.
robert4,
5
Miałem ten problem na zawsze i mogłem przysiąc, że w mojej ostatniej pracy znalazłem ustawienie, które sprawiło, że studio wizualne działało jak zaćmienie, w którym trzymałeś się wątku, z którym pracujesz, ale nie mogę go znaleźć ani żadnego odniesienia do tego. Zaczynam się zastanawiać, czy mi się śniło.
stu
7
-1, ponieważ pozwala to tylko na punkty przerwania, ale nie na debugowanie: krok powyżej / krok do nie działa w ten sposób do debugowania pojedynczego wątku.
Serge Rogatch
338

Oto co zrobiłem:

  1. Ustaw warunkowy punkt przerwania, o którym wiedziałem, że trafi tylko w poszukiwany wątek.

  2. Po osiągnięciu punktu przerwania i przejściu do żądanego wątku, w oknie Wątki programu Visual Studio (podczas debugowania, Debuguj -> Windows -> Wątki), Ctrl+ A(aby wybrać wszystkie wątki), a następnie Ctrl+ kliknij wątek, w którym aktualnie się znajdujesz . Powinieneś mieć wszystkie wątki oprócz tego, który chcesz debugować.

  3. Kliknij prawym przyciskiem myszy i wybierz „Zatrzymaj”.

Teraz Visual Studio będzie tylko przechodzić przez rozmrożony wątek. Wydaje się, że robi się to znacznie wolniej, prawdopodobnie dlatego, że musi przechodzić przez wszystkie zamrożone wątki, ale przyniosło pewne zdrowie psychiczne podczas mojego wielowątkowego debugowania.

Matt Faus
źródło
1
To nie działa dla mnie w kontekście, w którym mam około 8 zadań działających w różnych wątkach. Zatrzymuję wszystkie inne wątki i „przechodzę”, ale IDE zawiesza się na chwilę, a następnie przeskakuje do innego wątku.
Meta-Knight
3
@Diego: Nie pracuję już nad projektem, ale jeśli ma on zamrozić wszystkie wątki oprócz jednego, zmieni to scenariusz, który spowodował błąd, ponieważ wątki były komplementarne w sytuacji błędnej. Chociaż jest to eleganckie rozwiązanie, wydaje się, że ta funkcja powinna zostać osadzona w VS.
Xaqron,
3
@ Meta-Knight Powinieneś zamrozić wszystkie wątki oprócz Głównego. Jeśli zrobisz tak, IDE nie zostanie zamrożone
Alex Zhukovskiy
15

Właśnie wydałem rozszerzenie Visual Studio 2010+, które robi dokładnie to, czego szukasz. I to za darmo :).

Prezentacja

To rozszerzenie Visual Studio dodaje dwa skróty i przyciski paska narzędzi, aby umożliwić programistom łatwe skupienie się na pojedynczych wątkach podczas debugowania aplikacji wielowątkowych.

To znacznie zmniejsza potrzebę ręcznego przejścia do okna Wątki, aby zamrozić / rozmrozić wszystkie wątki oprócz tego, którego należy przestrzegać, a zatem pomaga poprawić wydajność.

cechy

Ogranicz dalsze wykonywanie tylko do bieżącego wątku. Zamrozi wszystkie pozostałe wątki. Skrót: CTRL + T + T lub przycisk Płatek śniegu. Przejdź do następnego pojedynczego wątku (na podstawie identyfikatora). Zmienia bieżący wątek i zamraża wszystkie pozostałe wątki. Skrót: CTRL + T + J lub przycisk Dalej.

Sprawdź to tutaj w galerii , na oficjalnej stronie lub w repozytorium Github .

Erwin Mayer
źródło
Której wersji VS używasz?
Erwin Mayer,
Zainstalowałem rozszerzenie, ale nie udało mi się go uruchomić (w moim bieżącym projekcie korzystam z VS2010). [Nawiasem mówiąc, moim zdaniem problem z aktywowaniem wątków dzieje się po utworzeniu wątków, jest to prawdopodobnie standardowe zachowanie, więc usunąłem mój poprzedni komentarz].
wytrzyj
3
Sprawdzę to. Być może jesteś jedyną osobą na świecie, która podjęła próbę rozwiązania jednego z największych błędów debugowania Microsoft.
stu
Niestety, nie zostanie zainstalowany na vs2012. Czy masz nowszą wersję, czy chcesz udostępnić kod źródłowy, abym mógł go sam zbudować?
stu
@stu Kod źródłowy znajduje się na Codeplex tutaj: singlethread.codeplex.com powinien działać na VS 2012 i VS 2013, ale go nie zaktualizowałem (nikt tego nie prosił i sam nie potrzebowałem). Jeśli możesz sprawić, że będzie on działał łatwo z VS 2012+ i dokonaj zatwierdzenia w Codeplex, to mogę go również przesłać w Galerii.
Erwin Mayer,
13

Jeśli spawanych jest wiele wątków, jak w przypadku aplikacji internetowej, odpowiedzi @MattFaus nie będą działać. Zamiast tego zrobiłem to

  • Ustaw punkt przerwania, aby przerwać wątek w żądanej funkcji.
  • Gdy wątek dotrze do punktu przerwania i zostanie zatrzymany, usuwam punkt przerwania i kontynuuję debugowanie za pomocą F8, F10 i F11, aby pozostałe wątki mogły działać.
Mikaël Mayer
źródło
Po przeczytaniu wszystkich najważniejszych anserwisów to obejście działało dla mnie.
Swanand Pangam
9

Nieco inne podejście, które użyłem:

  1. Utwórz normalny punkt przerwania i pozwól mu trafić
  2. Poszukaj w oknie wątków identyfikatora zarządzanego wątku, w którym debugujesz
  3. Kliknij prawym przyciskiem myszy punkt przerwania w oknie punktów przerwania i wybierz filtr wyboru
  4. Wpisz ThreadId = xxx, gdzie xxx to identyfikator wątku od 2
  5. Możesz teraz debugować bez zatrzymywania innych wątków i bez uderzania w punkt przerwania

Zakłada się, że masz czas na wykonanie powyższych czynności, zanim drugi wątek osiągnie punkt przerwania. Jeśli nie, a inne wątki osiągną punkt przerwania, zanim zrobisz powyższe, możesz kliknąć je prawym przyciskiem myszy w oknie wątków i wybrać opcję zamrożenia.

Matt
źródło
3
+1. „Zakłada się, że masz czas ... zanim drugi wątek osiągnie punkt przerwania”. Zawijam średnik w zamku i umieszczam punkt przerwania na średniku. Kiedy punkt przerwania zostanie osiągnięty po raz pierwszy, wyłączam punkt przerwania. Z powodu blokady żadne inne wątki nie mogą wejść. lock(m_someObject) { ; }
bluedog
Aby zaoszczędzić Google, okno wątków znajduje się w obszarze Debugowanie> Windows> Wątki.
Gabe,
2

W VS 2019:

  1. Ustaw gdzieś punkt przerwania.
  2. Naciskaj F5 (kontynuuj), aż pojawi się Twój wątek.
  3. Kliknij punkt przerwania, aby go usunąć.
  4. Możesz przesunąć nić za pomocą F10 lub F11.
Gozo
źródło
Działa również dla VS2015!
pingwin prehistoryczny
1

Sugeruję dodanie innej instancji aplikacji na serwerze na żywo, na tym samym sprzęcie lub na nowym komputerze (klastrowanie), a następnie debugowanie tylko tej instancji. Nie dodałbym punktu przerwania w kodzie, który uruchamiają użytkownicy. Jeśli to nie jest opcja, dodałbym więcej śledzenia.

Jeśli jednak jest to absolutnie konieczne i potrzebujesz statystyki rozwiązania, jestem pewien, że możesz dodać punkt przerwania, który pęka tylko wtedy, gdy żądanie pochodzi z twojego adresu IP. Zrobiłbyś to, dodając warunkowy punkt przerwania, który sprawdza HttpContext.Request.UserHostAddress. Pamiętaj jednak, że znacznie spowalnia to działanie aplikacji.

steinar
źródło
Właśnie tego próbowałem. Problem polega na tym, że ta instancja nie działa w tej samej domenie (działającej na IP lub innej domenie), co prowadzi do wielu problemów z certyfikatami (SSL, WCF, ...), a także przy niskim obciążeniu sytuacja buggy nigdy się nie zdarza!
Xaqron,
Przepraszam, nie jestem pewien, który z nich próbowałeś, czy próbowałeś warunkowego punktu przerwania?
steinar
Tak, nazwałem je na podstawie zarządzanego identyfikatora, aby zapewnić wyjątkowość. Wtedy trudno zgadnąć, który identyfikator jest przypisany i ustawić warunek na podstawie domysły. Czasami zgadywanie jest bliskie, a czasem zajmuje dużo czasu, aby złapać nić.
Xaqron,
1

Jeśli nie chcesz zatrzymać wszystkich innych wątków (być może dołączasz debuger programu Visual Studio do działającej aplikacji, która musi odpowiadać na żądania), możesz użyć makra, które automatycznie tworzy i usuwa punkty przerwania.

Jest to sugerowane w odpowiedzi na pytanie Przepełnienie stosu „Krok ponad” podczas debugowania programów wielowątkowych w Visual Studio .

Jednak link wyjaśnia tylko, jak debugować wiersz po wierszu. Sugeruję zmodyfikowanie makra (jeśli czujesz się swobodnie), aby zmodyfikować wszystkie punkty przerwania (na przykład w danym zakresie linii), aby zatrzymać tylko w bieżącym wątku.

kamaradclimber
źródło
1

Myślę, że jest to nieco inne w Visual Studio 2015. Zmienili kilka rzeczy w punktach przerwania, ale oto jak zastosować zaakceptowaną odpowiedź z hzdbyte (powyżej):

W punkcie przerwania na marginesie kodowania kliknij prawym przyciskiem myszy> Warunki> Zmień z „Wyrażenie warunkowe” na „Filtruj”. Pozwala to na filtrowanie według ThreadId.

Alternatywnie w punkcie przerwania w oknie Punkty przerwania kliknij prawym przyciskiem myszy> Ustawienia> zaznacz pole Warunki i wykonaj powyższe czynności.

Patelos
źródło
1

Ustaw warunek punktu przerwania, klikając prawym przyciskiem myszy boczny pasek linii. Wybierz „Warunek” i wprowadź w cudzysłowie:

System.Threading.Thread.CurrentThread.Name == "nazwa_wątku”

Alternatywnie możesz zrobić to samo, pobierając „Zarządzany identyfikator” wątku z okna „Wątki” i użyć:

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

James Sheridan
źródło