Поделиться через


Начало отладки многопоточных приложений (C#, Visual Basic, C++)

Visual Studio предоставляет несколько средств и элементов пользовательского интерфейса, помогающих в отладке многопоточных приложений. В этом учебнике показано, как использовать маркеры потоков, окно Параллельные стеки, окно Параллельные контрольные значения, условные точки останова и точки останова с фильтром. В этом руководстве описаны функции Visual Studio для отладки многопоточных приложений.

В этих двух статьях содержатся дополнительные сведения об использовании других многопоточных средств отладки:

Первым шагом является создание многопоточного проекта приложения.

Создание проекта многопоточного приложения

  1. Откройте Visual Studio и создайте новый проект.

    Если окно запуска не открыто, выберите Файл >Окно запуска.

    На начальном экране выберите Создать проект.

    В поле поиска окна Создание проекта введите консоль. Затем выберите C#, C++ или Visual Basic в списке языков и Windows в списке платформ.

    После применения фильтров языка и платформы выберите шаблон консольного приложения для .NET или C++, а затем нажмите кнопку "Далее".

    Примечание.

    Если нужный шаблон проекта отсутствует, перейдите в меню Сервис>Получить средства и компоненты..., после чего запустится Visual Studio Installer. Выберите рабочую нагрузку Разработка классических приложений .NET или Разработка классических приложений на C++, а затем нажмите кнопку Изменить.

    В поле Имя проекта окна Настроить новый проект введите MyThreadWalkthroughApp. Затем щелкните Далее или Создать в зависимости от того, какой вариант доступен.

    Для проекта .NET Core или .NET 5+ выберите рекомендуемую целевую платформу или .NET 8, а затем нажмите кнопку "Создать".

    Появится новый проект консольного приложения. Когда проект будет создан, откроется файл исходного кода. В зависимости от выбранного языка файл исходного кода может называться Program.cs, MyThreadWalkthroughApp.cpp или Module1.vb.

  2. Удалите код, отображаемый в исходном файле, и замените его следующим обновленным кодом. Выберите соответствующий фрагмент кода для конфигурации кода.

    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. В меню File (Файл) выберите команду Save All (Сохранить все).

  4. (Только для Visual Basic) В обозревателе решений (справа) щелкните правой кнопкой мыши узел проекта и выберите Свойства. На вкладке Приложение измените Объект запуска, установив значение Простой.

Отладка многопоточного приложения

  1. В редакторе исходного кода найдите следующий фрагмент кода:

    Thread.Sleep(3000);
    Console.WriteLine();
    
  2. Щелкните левой кнопкой мыши в левой Thread.Sleep области или для C++, std::this_thread::sleep_for чтобы вставить новую точку останова.

    Красный кружок в поле означает, что точка останова установлена в этом месте.

  3. В меню Отладка выберите команду Начать отладку (F5).

    Visual Studio создаст решение, приложение начнет работать с подключенным отладчиком, а затем остановится в точке останова.

  4. В редакторе исходного кода найдите строку, содержащую точку останова.

Обнаружение маркера потока

  1. На панели инструментов отладки нажмите кнопку "Показать потоки" в исходном Показать потоки в исходном кодекоде.

  2. Дважды нажмите клавишу F11 , чтобы перейти к отладчику.

  3. Посмотрите на переплет в левой части окна. В этой строке обратите внимание на значок Маркер потока маркера потока, который напоминает два скрученных потока. маркер потока указывает, что некий поток остановлен в этом месте.

    Маркер потока может быть частично скрыт точкой останова.

  4. Наведите указатель мыши на маркер потока. Подсказка сообщает имя и идентификационный номер каждого остановившегося тут потока. В этом случае этим именем, скорее всего, будет <noname>.

    Снимок экрана: идентификатор потока в подсказке данных.

  5. Выберите маркер потока, чтобы просмотреть доступные параметры в контекстном меню.

Просмотр расположений потоков

В окне Параллельные стеки можно переключаться между представлением потоков и представлением задач (для программирования на основе задач), а также просматривать сведения о стеке вызовов для каждого потока. В этом приложении можно использовать представление "Потоки".

  1. Откройте окно Параллельные стеки, выбрав Отладка>Windows>Параллельные стеки. Вы увидите примерно следующее. Точные сведения могут отличаться в зависимости от текущего расположения каждого потока, оборудования и языка программирования.

    Снимок экрана: окно параллельных стеков.

    В этом примере слева направо отображаются следующие сведения об управляемом коде.

    • Текущий поток (желтая стрелка) ввел ServerClass.InstanceMethod. Идентификатор потока и кадр стека потока можно просмотреть, наведите указатель мыши ServerClass.InstanceMethod.
    • Поток 31724 ожидает блокировки, принадлежащей Thread 20272.
    • Основной поток (левая сторона) остановлен на [внешнем коде], который можно просмотреть подробно, если вы выберете "Показать внешний код".

    Окно

    В этом примере слева направо отображаются следующие сведения об управляемом коде.

    • Основной поток (левая сторона) остановлен Thread.Start, где точка остановки определяется значком Маркер потокамаркера потока.
    • Два потока вошли в ServerClass.InstanceMethod, один из которых является текущим потоком (желтая стрелка), а другой поток остановлен в Thread.Sleep.
    • Новый поток (справа) также запускается, но останавливается в ThreadHelper.ThreadStart.
  2. Чтобы просмотреть потоки в представлении списка, выберите "Отладка>потоков Windows".>

    Снимок экрана: окно потоков.

    В этом представлении можно легко увидеть, что поток 20272 является основным потоком и в настоящее время находится во внешнем коде, в частности , System.Console.dll.

    Примечание.

    Дополнительные сведения об использовании окна "Потоки" см. в пошаговом руководстве. Отладка многопоточного приложения.

  3. Щелкните правой кнопкой мыши записи в окне параллельных стеков или потоков, чтобы просмотреть доступные параметры в контекстном меню.

    Вы можете выполнить различные действия из этих меню правой кнопкой мыши. В этом руководстве вы узнаете больше об этих сведениях в окне "Параллельные часы " (следующие разделы).

Установка контрольных значений для переменной

  1. Откройте окно Параллельные контрольные значения, выбрав Отладка>Windows>Параллельные контрольные значения>Параллельное контрольное значение 1.

  2. Выберите ячейку, в которой отображается <Add Watch> текст (или пустая ячейка заголовка в четвертом столбце) и введите data.

    Значения переменной данных для каждого потока отображаются в окне.

  3. Выберите ячейку, в которой отображается <Add Watch> текст (или пустая ячейка заголовка в пятом столбце) и введите count.

    Значения переменной count для каждого потока отображаются в окне. Если вы еще не видите эту информацию, попробуйте нажать клавишу F11 несколько раз, чтобы продвинуть выполнение потоков в отладчике.

    Окно параллельных контрольных значений

  4. Щелкните правой кнопкой мыши одну из строк в окне, чтобы просмотреть доступные параметры.

Установка и снятие отметки для потоков

Вы можете помечать важные потоки и пропускать другие потоки.

  1. В окне Параллельные контрольные значения выберите несколько строк, удерживая клавишу SHIFT.

  2. Щелкните правой кнопкой и выберите Пометить.

    Все выбранные потоки будут помечены. Теперь можно выполнить фильтрацию, чтобы отображались только помеченные потоки.

  3. В окне параллельного просмотра нажмите кнопку Отобразить помеченные потоки"Показать только помеченные потоки".

    В списке отображаются только помеченные потоки.

    Совет

    Пометив несколько потоков, щелкните правой кнопкой мыши строку кода в редакторе кода и выберите Запустить помеченные потоки до курсора. Обязательно выберите код, которого достигнут все потоки. Visual Studio приостанавливает потоки в выбранной строке кода, что упрощает управление порядком выполнения путем замораживания и размораживания потоков.

  4. Нажмите кнопку Показывать только помеченные потоки снова, чтобы вернуться в режим Показывать все потоки.

  5. Чтобы снять метки с потоков, щелкните правой кнопкой мыши один или несколько помеченных потоков в окне Параллельные контрольные значения и выберите Снять метку.

Замораживание и оттаивание выполнения потока

Совет

Вы можете замораживать и размораживать (приостанавливать и возобновлять) потоки для управления порядком их выполнения. Это поможет устранить проблемы параллелизма, такие как взаимоблокировки и состояния гонки.

  1. В окне Параллельные контрольные значения со всеми выбранными строками щелкните правой кнопкой мыши и выберите Заморозить.

    Во втором столбце для каждой строки отображается значок паузы. Значок паузы указывает, что поток заморожен.

  2. Отмените выбор всех остальных строк, выбрав только одну строку.

  3. Щелкните правой кнопкой мыши строку и выберите Разморозить.

    Значок приостановки исчезает в этой строке, что указывает, что поток больше не заморожен.

  4. Перейдите в редактор кода и нажмите клавишу F11. Выполняется только размороженный поток.

    Приложение также может создать экземпляры некоторых новых потоков. Все новые потоки не отложены и не заморожены.

Следуйте одному потоку с условными точками останова

Иногда полезно изучать выполнение одного потока в отладчике. Один из способов сделать это путем замораживания потоков, которые вы не заинтересованы. В некоторых сценариях может потребоваться выполнить один поток, не заморозив другие потоки, например для воспроизведения определенной ошибки. Чтобы следовать потоку без замораживания других потоков, необходимо избежать разрыва в коде, за исключением интересующего вас потока. Эту задачу можно выполнить, задав условную точку останова.

Можно задавать точки останова по различным условиям, например имя потока или идентификатор потока. Это может быть полезно, чтобы задать условие данных, которые вы знаете, уникально для каждого потока. Этот подход часто применяется во время отладки, если вы больше заинтересованы в определенном значении данных, чем в любом конкретном потоке.

  1. Щелкните правой кнопкой мыши созданную ранее точку останова и выберите пункт Условия.

  2. В окне Параметры точки останова введите data == 5 для условного выражения.

    Условная точка останова

    Совет

    Если вы больше заинтересованы в конкретном потоке, используйте для условия имя потока или идентификатор потока. Для этого в окне Параметры точки останова выберите Фильтр, а не Условное выражение и следуйте подсказкам по фильтрации. Возможно, вам потребуется присвоить имена потоков в коде приложения, так как идентификаторы потоков изменяются при перезапуске отладчика.

  3. Закройте окно Параметры точки останова.

  4. Нажмите кнопку "Перезапустить", чтобы перезапустить Перезагрузить приложение сеанс отладки.

    Вы разбиваетесь на код в потоке, где значение переменной данных равно 5. В окне Параллельные контрольные значения найдите желтую стрелку, указывающую текущий контекст отладчика.

  5. Теперь можно использовать шаг с обходом (F10) или пошаговое выполнение (F11) и проследить за выполнением одного потока.

    До тех пор, пока условие точки останова уникально для потока, и отладчик не попадает в другие точки останова на других потоках (может потребоваться отключить их), вы можете перейти к коду и перейти к коду без переключения на другие потоки.

    Примечание.

    При продвижении по отладчику будут выполняться все потоки. Однако отладчик не будет прерывать выполнение кода в других потоках, если только один из других потоков не достигнет точки останова.