Включить многопоточность visual studio

Обновлено: 07.07.2024

В этой статье я расскажу, как отлаживать многопоточные приложения в Visual Studio 2010, используя окна Parallel Tasks и Parallel Stacks. Эти окна помогут понять структуру выполнения многопоточных приложений и проверить правильность работы кода, который использует Task Parallel Library.

  • Как смотреть call stacks выполняемых потоков
  • Как посмотреть список заданий созданных в нашем приложении (System.Threading.Tasks.Task)
  • Как перемещаться в окнах отладки Parallel Tasks и Parallel Stacks
  • Узнаем интересные и полезные мелочи в отладки с vs2010

Осторожно, много картинок

Подготовка

Для тестов нам потребуется VS 2010. Изображения в этой статье получены с использованием процессора Intel Core i3

Код проекта

Код для языков VB и C++ можно найти на этой странице

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

static void A( object o)
B(o);
>
static void B( object o)
C(o);
>
static void C( object o)
int temp = ( int )o;

Interlocked.Increment( ref aa);
while (aa < 4)
;
>

//after
L(o);
>
static void F( object o)
G(o);
>
static void G( object o)
H(o);
>
static void H( object o)
// break here at the same time as E and K
Interlocked.Increment( ref bb);
Monitor.Enter(mylock);
while (bb < 3)
;
>
Monitor.Exit(mylock);

//after
L(o);
>
static void I( object o)
J(o);
>
static void J( object o)
int temp2 = ( int )o;

switch (temp2)
case 3:
t4.Wait();
break ;
case 4:
K(o);
break ;
default :
Debug.Assert( false , "fool2" );
break ;
>
>
static void K( object o)
// break here at the same time as E and H
Interlocked.Increment( ref bb);
Monitor.Enter(mylock);
while (bb < 3)
;
>
Monitor.Exit(mylock);

//after
L(o);
>
static void L( object oo)
int temp3 = ( int )oo;

switch (temp3)
case 1:
M(oo);
break ;
case 2:
N(oo);
break ;
case 4:
O(oo);
break ;
default :
Debug.Assert( false , "fool3" );
break ;
>
>
static void M( object o)
// breaks here at the same time as N and Q
Interlocked.Increment( ref cc);
while (cc < 3)
;
>
//BP3 - 1 in M, 2 in N, 3 still in J, 4 in O, 5 in Q
Debugger.Break();
Interlocked.Increment( ref cc);
while ( true )
Thread.Sleep(500); // for ever
>
static void N( object o)
// breaks here at the same time as M and Q
Interlocked.Increment( ref cc);
while (cc < 4)
;
>
R(o);
>
static void O( object o)
Task t5 = Task.Factory.StartNew(P, TaskCreationOptions.AttachedToParent);
t5.Wait();
R(o);
>
static void P()
Console .WriteLine( "t5 runs " + Task.CurrentId.ToString());
Q();
>
static void Q()
// breaks here at the same time as N and M
Interlocked.Increment( ref cc);
while (cc < 4)
;
>
// task 5 dies here freeing task 4 (its parent)
Console .WriteLine( "t5 dies " + Task.CurrentId.ToString());
waitFor5 = false ;
>
static void R( object o)
if (( int )o == 2)
//wait for task5 to die
while (waitFor5)

int i;
//spin up all procs
for (i = 0; i < pcount - 4; i++)
Task t = Task.Factory.StartNew(() => < while ( true );>);
Console .WriteLine( "Started task " + t.Id.ToString());
>

Task.Factory.StartNew(T, i + 1 + 5, TaskCreationOptions.AttachedToParent); //scheduled
Task.Factory.StartNew(T, i + 2 + 5, TaskCreationOptions.AttachedToParent); //scheduled
Task.Factory.StartNew(T, i + 3 + 5, TaskCreationOptions.AttachedToParent); //scheduled
Task.Factory.StartNew(T, i + 4 + 5, TaskCreationOptions.AttachedToParent); //scheduled
Task.Factory.StartNew(T, (i + 5 + 5).ToString(), TaskCreationOptions.AttachedToParent); //scheduled

//BP4 - 1 in M, 2 in R, 3 in J, 4 in R, 5 died
Debugger.Break();
>
else
Debug.Assert(( int )o == 4);
t3.Wait();
>
>
static void T( object o)
Console .WriteLine( "Scheduled run " + Task.CurrentId.ToString());
>
static Task t1, t2, t3, t4;
static int aa = 0;
static int bb = 0;
static int cc = 0;
static bool waitFor1 = true ;
static bool waitFor5 = true ;
static int pcount;
static S mylock = new S();
>

* This source code was highlighted with Source Code Highlighter .

Parallel Stacks Window: Threads View (Потоки)

Шаг 1

Копируем код в студию в новый проект и запускаем в режиме отладки (F5). Программа скомпилируется, запустится и остановится в первой точке остановки.
В меню Debug→Windows нажимаем на Parallel Stacks. С помощью этого окна мы можем посмотреть несколько стеков вызовов параллельных потоков. На следующем рисунке показано состояние программы в первой точке остановки. Окно Call Stack включается там же, в меню Debug→Windows. Эти окна доступны только во время отладки программы. Во время написания кода их просто не видно.

image

На картинке 4 потока сгруппированы вместе, потому что их стек фреймы (stack frames) принадлежат одному контексту метода (method context), это значит, что это один и тот же метод (А, B, C). Чтобы посмотреть ID потока нужно навести на заголовок «4 Threads». Текущий поток будет выделен жирным. Желтая стрелка означает активный стек фрейм в текущем потоке. Чтобы получить дополнительную информацию нужно навести мышкой.

image

Чтобы убрать лишнюю информацию или включить (например название модуля, сдвиг, имена параметров и их типы и пр.) нужно щелкнуть правой кнопкой мышки по заголовку таблицы в окошке Call Stack (аналогично делается во всем окружении Windows).

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

Шаг 2

Продолжаем выполнение программы до второй точки остановки (F5). На следующем слайде видно состояние потоков во второй точке.

image

На первом шаге 4 потока пришли из методов A, B и C. Эта информация до сих пор доступна в окне Parallel Stacks, но теперь эти 4 потока получили развитие дальше. Один поток продолжился в D, затем в E. Другой в F, G и потом в H. Два остальных в I и J, а оттуда один из них направился в K а другой пошел своим путем в non-user External Code.

Можно переключиться на другой поток, для этого двойной щелчек на потоке. Я хочу посмотреть метод K. Для этого двойной клик по MyCalss.K

image

Parallel Stacks покажет информацию, а отладчик в студии покажет код этого места. Нажимаем Toggle Method View и наблюдаем картину истории (иерархии) методов до K.

image

Шаг 3

Продолжаем отладку до 3 прерывания.

image

Когда несколько потоков приходят в один и тот же метод, но метод не в начале стека вызовов – он появляется в разных рамках, как это произошло с методом L.
Двойной клик по методу L. Получаем такую картинку

image

Метод L выделен жирным так же в двух других рамках, так что можно видеть где он еще появится. Чтобы увидеть какие фреймы вызывают метод L переключаем режим отображения (Toggle Method View). Получаем следующее:

image

В контекстном меню есть такие пункты как «Hexadecimal Display» и «Show External Code». При включении последнего режима диаграмма получается больше чем предыдущая и содержит информацию о non-user code.

image

Шаг 4

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

В этот раз диаграмма получится очень большой и на помощь приходит автоскролл, который сразу переводит на нужное место. The Bird's Eye View также помогает быстро ориентироваться в больших диаграммах. (маленькая кнопочка справа внизу). Авто зум и прочие радости помогают ориентироваться в действительно больших многопоточных приложениях.

image

Parallel Tasks Window и Tasks View в окне Parallel Stacks

Шаг 1

Завершаем работу программы (Shift + F5) или в меню отладки. Закрываем все лишние окошки с которыми мы экспериментировали в прошлом примере и открываем новые: Debug→Windows→Threads, Debug→Windows→Call Stack и лепим их к краям студии. Также открываем Debug→Windows→ Parallel Tasks. Вот что получилось в окне Parallel Tasks

image

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

Шаг 2

В предыдущий раз все задания были отмечены как выполняемые, сейчас 2 задания заблокированы по разным причинам. Чтобы узнать причину нужно навести мышь на задание.

image

Задание можно отметить флагом и следить за дальнейшим состоянием.

В окне Parallel Stack, которое мы использовали в предыдущем примере, есть переключатель просмотра с потоков на задания (слева вверху). Переключаем вид на Tasks

image

Шаг 3

image

Как видно из скриншота – новое задание 5 выполняется, а задачи 3 и 4 остановлены. Также можно изменить вид таблицы – правая кнопка мыши по заголовкам колонок. Если включить отображение предка задачи (Parent) то мы увидим, кто является предком задачи номер 5. Но для лучшей визуализации отношений можно включить специальный вид – ПКМ по колонке Parent→Parent Child View.

image

Окна Parallel Tasks и Parallel Stack – синхронизированы. Так что мы можем посмотреть какая задача в каком потоке выполняется. Например задача 4. Двойной клик по задаче 4 в окне Parallel Tasks, с этим кликом выполнится синхронизация с окном Parallel Stack и мы увидим такую картину

image

В окне Parallel Stack, в режиме задач можно перейти к поток. Для этого ПКМ на методе и Go To Thread. В нашем примере мы посмотрим что происходит с методом O.

image

Шаг 4

Продолжаем выполнение до следующей точки. Затем сортируем задачи по ID и видим следующее

image

В списке нет задачи 5, потому что она уже завершена. Задачи 3 и 4 ждут друг друга и зашли в тупик. Есть еще 5 новых задач от задачи 2, которые теперь запланированы на исполнение.

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

image

Задачи в списке задач можно сгруппировать. Например сгруппируем по статусу – ПКМ на колонке статус и Group by Status. Результат на скриншоте:

image

Еще несколько возможностей окошка Parallel Tasks: в контекстном меню можно заморозить задачи, можно заморозить основной поток задачи.

Заключение

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

Литература
Видео
Блог Daniel Moth

Спасибо за внимание и поменьше вам ошибок в многопоточных приложениях :)

В окне Потоки можно проверять потоки и работать с ними в отлаживаемом приложении. Пошаговые инструкции по использованию окна потоков см. в разделе Пошаговое руководство. Отладка с помощью окна потоков.

Использование окна потоков

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

Флаг. В этом непомеченном столбце можно пометить поток, которому планируется уделить особое внимание. Сведения о способе пометки потока см. в разделе Практическое руководство. Установка и снятие отметки для потоков.

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

Идентификатор. Отображает идентификационный номер для каждого потока.

Управляемый ИД. Отображает управляемый идентификационный номер для каждого управляемого потока.

Категория: Отображает категорию потоков: потоки пользовательского интерфейса, обработчики удаленного вызова процедур и рабочие потоки. Особая категория идентифицирует главный поток приложения.

Имя: Указывает каждый поток по имени, если оно имеется, или значение <No Name>.

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

Приоритет. Расширенный столбец (скрытый по умолчанию), отображающий приоритет, назначенный системой каждому потоку.

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

Счетчик приостановок. Расширенный столбец (скрытый по умолчанию), отображающий счетчик приостановок. Этот счетчик определяет, может ли поток выполняться. Дополнительные сведения о счетчиках приостановок см. в разделе Замораживание и размораживание потоков.

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

Идентификатор процесса. Расширенный столбец (скрытый по умолчанию), отображающий идентификатор процесса, к которому относится каждый поток.

Квалификатор транспорта. Расширенный столбец (скрытый по умолчанию), однозначно определяющий компьютер, к которому подключен отладчик.

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

  • Пока Visual Studio находится в режиме отладки, выберите меню Отладка, наведите указатель мыши на пункт Windows, а затем выберите Потоки.

Отображение или скрытие столбца

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

Отобразить только помеченные потоки

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

Отображение только помеченных потоков

  • Выберите Показывать только помеченные потоки на панели инструментов в верхней части окна Потоки. (Если вариант недоступен, сначала необходимо пометить некоторые потоки.)

Замораживание и размораживание потоков

Если поток заморожен, то система не начнет его выполнение, даже если будут доступны все ресурсы.

В машинном коде потоки могут быть приостановлены или возобновлены путем вызова функций Windows SuspendThread и ResumeThread . Или вызовите функции MFC CWinThread::SuspendThread и CWinThread::ResumeThread. Если вы вызываете SuspendThread или ResumeThread , будет изменен счетчик приостановок в окне Потоки. Счетчик приостановок не меняется при замораживании или размораживании собственного потока. В машинном коде поток не может выполняться, пока он не будет разморожен, а счетчик приостановок не будет равен нулю.

В управляемом коде счетчик приостановок изменяется при замораживании или размораживании потока. Если вы заморозите поток в управляемом коде, его счетчик приостановок будет равен 1. При замораживании потока в машинном коде его счетчик приостановок равен 0, если только не использовался вызов SuspendThread .

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

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

На панели инструментов, находящейся в верхней части окна Потоки, нажмите Заморозить потоки или Разморозить потоки.

Это действие влияет только на потоки, выбранные в окне Потоки.

Переключение на другой поток

Желтая стрелка указывает текущий поток (и размещение указателя выполнения). Зеленая стрелка с загнутым наконечником указывает, что поток, не являющийся текущим, имеет текущий контекст отладчика.

Переключение на другой поток

Выполните одно из следующих действий:

Дважды щелкните любой поток.

Щелкните правой кнопкой мыши поток и выберите пункт Переключиться на поток.

Группирование и сортировка потоков

При группировании потоков в таблице появляется заголовок для каждой группы. В заголовке содержится описание группы, например Рабочие потоки или Непомеченные потоки, и элемент управления "Дерево". Потоки-элементы каждой группы отображаются под заголовком группы. Если требуется скрыть потоки-элементы в какой-либо группе, можно свернуть эту группу с помощью элемента управления "Дерево".

Поскольку группирование имеет приоритет перед сортировкой, можно, например, группировать потоки по категориям, а затем по идентификаторам внутри каждой категории.

Сортировка потоков

На панели инструментов, находящейся в верхней части окна Потоки, нажмите кнопку в верхней части любого столбца.

Теперь потоки отсортированы по значениям в этом столбце.

Если требуется изменить порядок сортировки, нажмите кнопку еще раз.

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

Группирование потоков

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

Сортировка потоков в группах

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

В окне Потоки нажмите кнопку в верхней части любого столбца.

Теперь потоки отсортированы по значениям в этом столбце.

Сворачивание и разворачивание всех групп

  • На панели инструментов в верхней части окна Потоки, нажмите Развернуть группы или Свернуть группы.

Поиск конкретных потоков

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

Поиск конкретных потоков

В панели инструментов, находящейся в верхней части окна Потоки, перейдите в поле Поиск и выполните одно из следующих действий:

  • введите строку поиска и нажмите клавишу ВВОД
  • нажмите раскрывающийся список рядом с полем Поиск и выберите строку поиска из предыдущего поиска.

Чтобы включить в поиск полный стек вызова, выберите Поиск в стеке вызова (необязательно).

Отображение стека вызовов потоков и переключение между фреймами

В многопотоковых программах каждый поток имеет свой собственный стек вызовов. Окно Потоки обеспечивает удобный способ просмотра этих стеков.

Для визуального представления стека вызовов для каждого потока используйте окно Параллельные стеки.

Просмотр стека вызовов потока

В столбце Расположение нажмите перевернутый треугольник рядом с расположением потока.

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

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

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

Создайте следующий проект многопоточного приложения для использования в этом учебнике:

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

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

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

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

В верхней строке меню последовательно выберите Файл > Создать > Проект. В левой области диалогового окна Создание проекта выберите следующие элементы.

Введите имя, например MyThreadWalkthroughApp, и нажмите ОК.

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

Нажмите Файл > Сохранить все.

Начать отладку

Найдите следующие строки в исходном коде:

Установите точку останова на строке Console.WriteLine(); , щелкнув в левом поле или выбрав строку и нажав клавишу F9.

Точка останова отображается как красный кружок в левом поле рядом со строкой кода.

Выберите Отладка > Начать отладку или нажмите клавишу F5.

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

В режиме приостановки откройте окно Потоки, выбрав Отладка > Windows > Потоки. Чтобы открыть или просмотреть окно Потоки и другие окна отладки, необходимо находиться в сеансе отладки.

Проверка маркеров потоков

В исходном коде найдите строку Console.WriteLine(); .

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

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

Чтобы различать безымянные потоки, их можно переименовать в окне Потоки. Щелкните поток правой кнопкой мыши и выберите пункт Переименовать.

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

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

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

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

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

Чтобы открыть панель инструментов Место отладки, выберите Вид > Панели инструментов > Место отладки. Можно также щелкнуть правой кнопкой мыши в области панели инструментов и выбрать Место отладки.

Панель инструментов Место отладки содержит три поля: Процесс, Поток и Кадр стека. Откройте раскрывающийся список Поток и обратите внимание на количество потоков. В списке Поток выполняющийся в данный момент поток помечается символом > .

В окне исходного кода наведите указатель мыши на значок маркера потока в поле и выберите значок флага (или один из пустых значков флагов) в подсказке. Значок флага становится красным.

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

Показывать помеченные потоки

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

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

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

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

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

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

Окно потоков

Выберите значок флага, чтобы изменить состояние потока на "помечено" или "не помечено" в зависимости от его текущего состояния.

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

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

Другие функции окна "Потоки"

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

Вторым столбцом окна Потоки (без заголовка) является столбец Текущий поток. Желтая стрелка в этом столбце отмечает текущую точку выполнения.

В столбце Расположение показано, где каждый поток отображается в исходном коде. Щелкните стрелку "Развернуть" рядом с пунктом Расположение или наведите указатель мыши на пункт, чтобы отобразить частичный стек вызовов для этого потока.

Для графического представления стеков вызовов для потоков используйте окно Параллельные стеки. Чтобы открыть это окно, во время отладки выберите Отладка> Окна > Параллельные стеки.

Помимо пунктов Пометить, Снять метку и Снять метку для всех потоков, в контекстном меню для окна Поток есть следующие элементы.

  • Кнопка Показать потоки в исходном коде.
  • Шестнадцатеричное отображение, которое изменяет идентификатор потока в окне Потоки с десятичного на шестнадцатеричный формат. — немедленное переключение на выполнение этого потока.
  • Переименовать — изменение имени потока.
  • Команды Замораживание и размораживание.

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

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

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

Закрепление и снятие закрепления потоков:

В окне Потоки щелкните правой кнопкой мыши любой поток и нажмите Заморозить. Значок паузы в столбце Текущий поток указывает, что поток заморожен.

Выберите Столбцы на панели инструментов окна Потоки, а затем выберите Число приостановок, чтобы отобразить столбец Число приостановок. Значение числа приостановок для замороженного потока равно 1.

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

Значок паузы исчезает, а значение числа приостановок меняется на 0.

Переключение на другой поток

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

Переключение на другой поток

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

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

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

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

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

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

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

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

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

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

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

Пример, использующий Task (управляемый код) и среду выполнения с параллелизмом (C++), см. в разделе Пошаговое руководство. Отладка параллельного приложения. Для общих советов по отладке, которые относятся к большинству типов многопоточных приложений, ознакомьтесь с этим разделом и с пошаговым руководством.

Сначала вам требуется проект многопоточного приложения. См. пример ниже.

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

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

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

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

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

В верхней строке меню последовательно выберите Файл > Создать > Проект. В левой области диалогового окна Создание проекта выберите следующие элементы.

Введите имя, например MyThreadWalkthroughApp, и нажмите ОК.

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

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

В меню Файл выберите команду Сохранить все.

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

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

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

Щелкните левой кнопкой мыши в левом поле инструкции Thread.Sleep или std::this_thread::sleep_for , чтобы вставить новую точку останова.

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

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

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

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

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

Показать потоки в исходном коде

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

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

Маркер потока

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

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

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

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

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

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

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

Окно "Параллельные стеки"

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

Маркер потока

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Показывать помеченные потоки

В окне Параллельные контрольные значения выберите Показывать только помеченные потоки .

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

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

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

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

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

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

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

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

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

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

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

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

Изучение одного потока с условными точками останова

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

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

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

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

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

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

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

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

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

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

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

Читайте также: