Udostępnij za pośrednictwem


Wprowadzenie do debugowania aplikacji wielowątkowych (C#, Visual Basic, C++)

Program Visual Studio udostępnia kilka narzędzi i elementów interfejsu użytkownika, które ułatwiają debugowanie aplikacji wielowątkowych. W tym samouczku pokazano, jak używać znaczników wątków, okna Parallel Stacks, okna Parallel Watch, warunkowych punktów przerwania i filtrowanych punktów przerwania. Ukończenie tego samouczku zapoznaje Cię z funkcjami programu Visual Studio na potrzeby debugowania aplikacji wielowątkowych.

Te dwa artykuły zawierają dodatkowe informacje na temat korzystania z innych narzędzi debugowania wielowątkowego:

Pierwszym krokiem jest utworzenie wielowątkowego projektu aplikacji.

Tworzenie wielowątkowego projektu aplikacji

  1. Otwórz program Visual Studio i utwórz nowy projekt.

    Jeśli okno startowe nie jest otwarte, wybierz Plik>Okno startowe.

    W oknie uruchamiania wybierz pozycję Utwórz nowy projekt.

    W oknie Tworzenie nowego projektu wprowadź lub wpisz konsolę w polu wyszukiwania. Następnie wybierz pozycję C#, C++lub Visual Basic z listy Język, a następnie wybierz pozycję Windows z listy Platforma.

    Po zastosowaniu filtrów języka i platformy wybierz szablon Aplikacja konsolowa dla platformy .NET lub C++, a następnie wybierz przycisk Dalej.

    Uwaga / Notatka

    Jeśli nie widzisz poprawnego szablonu, przejdź do pozycji NarzędziaPobierz narzędzia >i funkcje..., co spowoduje otwarcie Instalatora programu Visual Studio. Wybierz pakiet roboczy Programowanie aplikacji klasycznych .NET lub Programowanie aplikacji klasycznych przy użyciu języka C++ , a następnie wybierz pozycję Modyfikuj.

    W oknie Konfigurowanie nowego projektu wpisz lub wprowadź ciąg MyThreadWalkthroughApp w polu Nazwa projektu . Następnie wybierz pozycję Dalej lub Utwórz, niezależnie od tego, która opcja jest dostępna.

    W przypadku projektu .NET Core lub .NET 5+ wybierz zalecaną platformę docelową lub platformę .NET 8, a następnie wybierz pozycję Utwórz.

    Pojawia się nowy projekt konsoli. Po utworzeniu projektu zostanie wyświetlony plik źródłowy. W zależności od wybranego języka plik źródłowy może być nazywany Program.cs, MyThreadWalkthroughApp.cpp lub Module1.vb.

  2. Usuń kod wyświetlany w pliku źródłowym i zastąp go następującym zaktualizowanym kodem. Wybierz odpowiedni fragment kodu dla Twojej konfiguracji.

    using System;
    using System.Threading;
    
    public class ServerClass
    {
    
        static int count = 0;
        // The method that will be called when the thread is started.
        public void InstanceMethod()
        {
            Console.WriteLine(
                "ServerClass.InstanceMethod is running on another thread.");
    
            int data = count++;
            // Pause for a moment to provide a delay to make
            // threads more apparent.
            Thread.Sleep(3000);
            Console.WriteLine(
                "The instance method called by the worker thread has ended. " + data);
        }
    }
    
    public class Simple
    {
        public static void Main()
        {
            for (int i = 0; i < 10; i++)
            {
                CreateThreads();
            }
        }
        public static void CreateThreads()
        {
            ServerClass serverObject = new ServerClass();
    
            Thread InstanceCaller = new Thread(new ThreadStart(serverObject.InstanceMethod));
            // Start the thread.
            InstanceCaller.Start();
    
            Console.WriteLine("The Main() thread calls this after "
                + "starting the new InstanceCaller thread.");
    
        }
    }
    
  3. W menu Plik wybierz pozycję Zapisz wszystko.

  4. (Tylko Visual Basic) W Eksploratorze rozwiązań (okienko po prawej stronie) kliknij prawym przyciskiem myszy węzeł projektu, a następnie wybierz polecenie Właściwości. Na karcie Aplikacja zmień obiekt startowy na Prosty.

Debugowanie aplikacji wielowątkowej

  1. W edytorze kodu źródłowego poszukaj następującego fragmentu kodu:

    Thread.Sleep(3000);
    Console.WriteLine();
    
  2. Kliknij lewym przyciskiem myszy w lewy margines instrukcji Thread.Sleep lub dla języka C++, std::this_thread::sleep_for, aby wstawić nowy punkt przerwania.

    W rynnie czerwony okrąg wskazuje, że punkt przerwania jest ustawiony w tej lokalizacji.

  3. W menu Debugowanie wybierz pozycję Rozpocznij debugowanie (F5).

    Program Visual Studio kompiluje rozwiązanie, aplikacja zaczyna działać z dołączonym debugerem, a następnie aplikacja zatrzymuje się w punkcie przerwania.

  4. W edytorze kodu źródłowego znajdź wiersz zawierający punkt przerwania.

Odkryj znacznik wątku

  1. Na pasku narzędzi debugowania wybierz przycisk Pokaż wątki w źródlePokaż wątki w źródle.

  2. Naciśnij F11 dwa razy, aby przejść do debugera.

  3. Spójrz na rynnę po lewej stronie okna. W tym wierszu zwróć uwagę na ikonę znacznika wątkuZnacznik wątku, która przypomina dwa skręcone nici. Znacznik wątku wskazuje, że w tej lokalizacji zatrzymano wątek.

    Znacznik wątku może być częściowo ukryty przez punkt przerwania.

  4. Umieść wskaźnik na znaczniku wątku. Pojawi się podpowiedź informująca o nazwie i numerze identyfikatora wątku dla każdego zatrzymanego wątku. W tym przypadku nazwa to prawdopodobnie <noname>.

    Zrzut ekranu przedstawiający identyfikator wątku w etykietce danych.

  5. Wybierz znacznik wątku, aby wyświetlić dostępne opcje w menu skrótów.

Wyświetlanie lokalizacji wątków

W oknie Stosy równoległe można przełączać się między widokiem Wątki i (w przypadku programowania opartego na zadaniach) widoku Zadania, a także wyświetlić informacje o stosie wywołań dla każdego wątku. W tej aplikacji możemy użyć widoku Wątków.

  1. Otwórz okno Stosy równoległe, wybierając Debug>Windows>Stosy równoległe. Powinna zostać wyświetlona zawartość podobna do poniższej. Dokładne informacje mogą się różnić w zależności od bieżącej lokalizacji każdego wątku, sprzętu i języka programowania.

    Zrzut ekranu przedstawiający okno stosów równoległych.

    W tym przykładzie od lewej do prawej są widoczne następujące informacje dotyczące kodu zarządzanego:

    • Bieżący wątek (żółta strzałka) wszedł do ServerClass.InstanceMethod. Identyfikator wątku i ramkę stosu wątku można wyświetlić, umieszczając wskaźnik myszy nad ServerClass.InstanceMethod.
    • Wątek 31724 oczekuje na blokadę, którą posiada wątek 20272.
    • Wątek główny (po lewej stronie) został zatrzymany na stronie [Kod zewnętrzny], który można wyświetlić szczegółowo, jeśli wybierzesz pozycję Pokaż kod zewnętrzny.

    Okno stosów równoległych

    W tym przykładzie od lewej do prawej są widoczne następujące informacje dotyczące kodu zarządzanego:

    • Wątek główny (po lewej stronie) został zatrzymany na Thread.Start, gdzie punkt zatrzymania jest identyfikowany przez ikonę znacznika wątku Thread Marker.
    • Dwa wątki weszły do ServerClass.InstanceMethod, jeden to bieżący wątek (oznaczony żółtą strzałką), podczas gdy drugi wątek zatrzymał się w Thread.Sleep.
    • Nowy wątek (po prawej stronie) jest również rozpoczynany, ale jest zatrzymany na ThreadHelper.ThreadStart.
  2. Aby wyświetlić wątki w widoku listy, wybierz Debug>Windows>Threads.

    Zrzut ekranu przedstawiający okno ThreadsWindow.

    W tym widoku można łatwo zobaczyć, że wątek 20272 jest wątkiem głównym i znajduje się obecnie w kodzie zewnętrznym, w szczególności System.Console.dll.

    Uwaga / Notatka

    Aby uzyskać więcej informacji na temat korzystania z okna Wątki , zobacz Przewodnik: debugowanie aplikacji wielowątkowej.

  3. Kliknij prawym przyciskiem myszy wpisy w oknie Stosy równoległe lub Wątki, aby wyświetlić dostępne opcje w menu skrótów.

    Z tych menu po kliknięciu prawym przyciskiem myszy można wykonywać różne akcje. W tym samouczku zapoznasz się z bardziej szczegółowymi informacjami w oknie Monitorowanie równoległe (następne sekcje).

Ustawienie obserwacji na zmiennej

  1. Otwórz okno Równoległy Podgląd, wybierając Debuguj>Windows>Równoległy Podgląd>Równoległy Podgląd 1.

  2. Wybierz komórkę, w której widzisz <Add Watch> tekst (lub pustą komórkę nagłówka w czwartej kolumnie) i wprowadź data.

    Wartości zmiennej danych dla każdego wątku są wyświetlane w oknie.

  3. Wybierz komórkę, w której zostanie wyświetlony <Add Watch> tekst (lub pusta komórka nagłówka w piątej kolumnie), a następnie wprowadź wartość count.

    Wartości zmiennej count dla każdego wątku są wyświetlane w oknie. Jeśli nie widzisz jeszcze takiej ilości informacji, spróbuj nacisnąć F11 parę razy, aby przesunąć wykonanie wątków w debugerze.

    Równoległe okno czujki

  4. Kliknij prawym przyciskiem myszy jeden z wierszy w oknie, aby wyświetlić dostępne opcje.

Oznacz lub usuń oznaczenie wątków

Wątki można flagować, aby śledzić ważne wątki i ignorować inne wątki.

  1. W oknie Zegarek równoległy przytrzymaj naciśnięty Shift i wybierz wiele wierszy.

  2. Kliknij prawym przyciskiem myszy i wybierz Oznacz.

    Wszystkie wybrane wątki są oflagowane. Teraz możesz filtrować, aby wyświetlić tylko oflagowane wątki.

  3. W oknie Obserwacja równoległa wybierz przycisk Pokaż tylko oflagowane wątkiShow Flagged Threads.

    Na liście są wyświetlane tylko oflagowane wątki.

    Wskazówka

    Po oflagowaniu niektórych wątków możesz kliknąć prawym przyciskiem myszy wiersz kodu w edytorze kodu i wybrać polecenie Uruchom oflagowane wątki do kursora. Upewnij się, że wybrano kod, z którym będą dostępne wszystkie oflagowane wątki. Program Visual Studio wstrzyma wątki w wybranym wierszu kodu, co ułatwia kontrolowanie kolejności wykonywania przez zamrażanie i odmrażanie wątków.

  4. Ponownie wybierz przycisk Pokaż tylko oflagowane wątki , aby powrócić do trybu Pokaż wszystkie wątki .

  5. Aby usunąć oznaczenie wątków, kliknij prawym przyciskiem myszy co najmniej jeden oznaczony wątek w oknie Monitor równoległy i wybierz polecenie Usuń oznaczenie.

Blokowanie i rozmrażanie wykonania wątku

Wskazówka

Możesz zablokować i rozmrozić (wstrzymać i wznowić) wątki, aby kontrolować kolejność, w której wątki wykonują pracę. Może to pomóc w rozwiązaniu problemów ze współbieżnością, takich jak zakleszczenia i warunki wyścigu.

  1. W oknie Równoległy zegarek, mając zaznaczone wszystkie wiersze, kliknij prawym przyciskiem myszy i wybierz opcję Zablokuj.

    W drugiej kolumnie zostanie wyświetlona ikona wstrzymania dla każdego wiersza. Ikona wstrzymania wskazuje, że wątek jest zamrożony.

  2. Usuń zaznaczenie wszystkich innych wierszy, wybierając tylko jeden wiersz.

  3. Kliknij prawym przyciskiem myszy na wiersz i wybierz polecenie Odmroź.

    Ikona wstrzymania odchodzi w tym wierszu, co oznacza, że wątek nie jest już zamrożony.

  4. Przejdź do edytora kodu i naciśnij F11. Tylko niezamrożony wątek działa.

    Aplikacja może również zainicjować nowe wątki. Wszystkie nowe wątki są nieoznaczone i nie są zamrożone.

Śledź jeden wątek z warunkowymi punktami przerwania

Śledzenie pojedynczego wątku w debugerze może być pomocne. Jednym ze sposobów, aby to zrobić, jest zamrażanie wątków, których nie interesujesz. W niektórych scenariuszach może być konieczne wykonanie pojedynczego wątku bez zamrażania innych wątków, na przykład w celu odtworzenia konkretnej usterki. Aby postępować zgodnie z wątkiem bez zamrażania innych wątków, należy unikać włamywania się do kodu z wyjątkiem wątku, który cię interesuje. To zadanie można wykonać, ustawiając warunkowy punkt przerwania.

Punkty przerwania można ustawić w różnych warunkach, takich jak nazwa wątku lub identyfikator wątku. Pomocne może być ustawienie warunku na dane, które znasz jako unikatowe dla każdego wątku. Takie podejście jest typowe podczas debugowania, gdy interesuje Cię określona wartość danych niż w jakimkolwiek konkretnym wątku.

  1. Kliknij prawym przyciskiem myszy utworzony wcześniej punkt przerwania i wybierz pozycję Warunki.

  2. W oknie Ustawienia punktu przerwania wprowadź data == 5 wartość dla wyrażenia warunkowego.

    Punkt przerwania warunkowego

    Wskazówka

    Jeśli interesuje Cię konkretny wątek, użyj nazwy wątku lub identyfikatora wątku dla warunku. Aby to zrobić w oknie Ustawienia punktu przerwania, wybierz pozycję Filtr zamiast wyrażenia warunkowego i postępuj zgodnie z wskazówkami dotyczącymi filtru. Możesz nazwać wątki w kodzie aplikacji, ponieważ identyfikatory wątków zmieniają się po ponownym uruchomieniu debugera.

  3. Zamknij okno Ustawienia punktu przerwania .

  4. Wybierz przycisk Uruchom ponownie aplikację, aby ponownie uruchomić sesję debugowania.

    Należy przerwać działanie kodu w wątku, w którym wartość zmiennej danych jest równa 5. W oknie Monitorowanie równoległe wyszukaj żółtą strzałkę wskazującą bieżący kontekst debugera.

  5. Teraz możesz przejść przez kod (F10) i przejść do kodu (F11) i postępować zgodnie z wykonywaniem pojedynczego wątku.

    Tak długo, jak warunek punktu przerwania jest unikatowy dla wątku, a debuger nie osiąga żadnych innych punktów przerwania w innych wątkach (może być konieczne ich wyłączenie), możesz przejść przez kod i przejść do kodu bez przełączania się do innych wątków.

    Uwaga / Notatka

    Gdy przesuniesz debugger, wszystkie wątki zostaną uruchomione. Jednak debuger nie zatrzyma się na kodzie w innych wątkach, chyba że jeden z innych wątków osiągnie punkt przerwania.