Passo a passo: Depurando um aplicativo paralelo
Esta explicação passo a passo mostra como usar o Tarefas paralelas e Paralela pilhas windows para depurar um aplicativoem paralelo.Essas janelas ajudam a compreender e verificar o comportamento de tempo de execução de código que usa o Biblioteca paralela de tarefas (TPL) ou o Tempo de execução de concorrência.Esta explicação passo a passo fornece código de exemplo que tem pontos de interrupção internos.Depois que o código é interrompida, a explicação passo a passo mostra como usar o Tarefas paralelas e Paralela pilhas windows examiná-lo.
Esta explicação passo a passo ensina essas tarefas:
Como exibir as pilhas de chamadas de todos os threads em um modo de exibição.
Como exibir a lista de System.Threading.Tasks.Task instâncias que são criadas em seu aplicativo.
Como exibir as pilhas de chamadas real das tarefas em vez de threads.
Como navegar até o código da Tarefas paralelas e Paralela pilhas windows.
Como os windows lidar com escala por meio do agrupamento, zoom e outros recursos relacionados.
Pré-requisitos
Esta explicação passo a passo presume que Apenas Meu Código está habilitado.No Ferramentas menu, clique em Opções, expandir o Debugging nó, selecione Gerale selecione Permitir que o Apenas Meu Código (somente gerenciado). Se você não definir esse recurso, você ainda pode usar este passo a passo, mas os resultados podem ser diferentes das ilustrações.
Exemplo C#
Se você usar a amostra de C#, este passo a passo também pressupõe que o código externo é oculto.Para indicar se o código externo é exibido, clique com o botão direito do nome tabela de cabeçalho da Call Stack janela, em seguida, marque ou desmarque Show External Code. Se você não definir esse recurso, você ainda pode usar este passo a passo, mas os resultados podem ser diferentes das ilustrações.
Exemplo de C++
Se você usar a amostra de C++, você pode ignorar as referências ao código externo neste tópico.Código externo só se aplica a amostra de C#.
Ilustrações
As ilustrações deste tópico é gravado em um computador quad-core, executando o exemplo C#.Embora você possa usar outras configurações para concluir este passo a passo, as ilustrações podem diferir do que é exibido em seu computador.
Criando o projeto de amostra
Esta explicação passo a passo o código de exemplo é para um aplicativo que não faz nada.O meta é apenas entender como usar a ferramenta windows para depurar um aplicativoem paralelo.
Para criar o projeto de exemplo
No Visual Studio, no menu Arquivo, aponte para Novo e, em seguida, clique em Projeto.
No Modelos instaladosopainel, selecione Visual C#, Visual Basicou Visual C++. Para os idiomas gerenciado , certifique-se que .NET Framework 4 é exibido na caixa de framework.
Selecione Aplicativo de Console e, em seguida, clique em OK.Permanecem na configuraçãode depuração, que é o padrão.
Abra o arquivo de código. vb,. cs ou. cpp no projeto.Exclua seu conteúdo para criar um arquivo de código vazio.
Cole o seguinte código para sua linguagem escolhida para o arquivo de código vazio.
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Diagnostics
Module S
Sub Main()
pcount = Environment.ProcessorCount
Console.WriteLine("Proc count = " + pcount.ToString())
ThreadPool.SetMinThreads(4, -1)
ThreadPool.SetMaxThreads(4, -1)
t1 = New Task(AddressOf A, 1)
t2 = New Task(AddressOf A, 2)
t3 = New Task(AddressOf A, 3)
t4 = New Task(AddressOf A, 4)
Console.WriteLine("Starting t1 " + t1.Id.ToString())
t1.Start()
Console.WriteLine("Starting t2 " + t2.Id.ToString())
t2.Start()
Console.WriteLine("Starting t3 " + t3.Id.ToString())
t3.Start()
Console.WriteLine("Starting t4 " + t4.Id.ToString())
t4.Start()
Console.ReadLine()
End Sub
Sub A(ByVal o As Object)
B(o)
End Sub
Sub B(ByVal o As Object)
C(o)
End Sub
Sub C(ByVal o As Object)
Dim temp As Integer = o
Interlocked.Increment(aa)
While (aa < 4)
End While
If (temp = 1) Then
' BP1 - all tasks in C
Debugger.Break()
waitFor1 = False
Else
While (waitFor1)
End While
End If
Select Case temp
Case 1
D(o)
Case 2
F(o)
Case 3, 4
I(o)
Case Else
Debug.Assert(False, "fool")
End Select
End Sub
Sub D(ByVal o As Object)
E(o)
End Sub
Sub E(ByVal o As Object)
' break here at the same time as H and K
While (bb < 2)
End While
'BP2 - 1 in E, 2 in H, 3 in J, 4 in K
Debugger.Break()
Interlocked.Increment(bb)
'after
L(o)
End Sub
Sub F(ByVal o As Object)
G(o)
End Sub
Sub G(ByVal o As Object)
H(o)
End Sub
Sub H(ByVal o As Object)
' break here at the same time as E and K
Interlocked.Increment(bb)
Monitor.Enter(mylock)
While (bb < 3)
End While
Monitor.Exit(mylock)
'after
L(o)
End Sub
Sub I(ByVal o As Object)
J(o)
End Sub
Sub J(ByVal o As Object)
Dim temp2 As Integer = o
Select Case temp2
Case 3
t4.Wait()
Case 4
K(o)
Case Else
Debug.Assert(False, "fool2")
End Select
End Sub
Sub K(ByVal o As Object)
' break here at the same time as E and H
Interlocked.Increment(bb)
Monitor.Enter(mylock)
While (bb < 3)
End While
Monitor.Exit(mylock)
'after
L(o)
End Sub
Sub L(ByVal oo As Object)
Dim temp3 As Integer = oo
Select Case temp3
Case 1
M(oo)
Case 2
N(oo)
Case 4
O(oo)
Case Else
Debug.Assert(False, "fool3")
End Select
End Sub
Sub M(ByVal o As Object)
' breaks here at the same time as N and Q
Interlocked.Increment(cc)
While (cc < 3)
End While
'BP3 - 1 in M, 2 in N, 3 still in J, 4 in O, 5 in Q
Debugger.Break()
Interlocked.Increment(cc)
While (True)
Thread.Sleep(500) ' for ever
End While
End Sub
Sub N(ByVal o As Object)
' breaks here at the same time as M and Q
Interlocked.Increment(cc)
While (cc < 4)
End While
R(o)
End Sub
Sub O(ByVal o As Object)
Dim t5 As Task = Task.Factory.StartNew(AddressOf P, TaskCreationOptions.AttachedToParent)
t5.Wait()
R(o)
End Sub
Sub P()
Console.WriteLine("t5 runs " + Task.CurrentId.ToString())
Q()
End Sub
Sub Q()
' breaks here at the same time as N and M
Interlocked.Increment(cc)
While (cc < 4)
End While
' task 5 dies here freeing task 4 (its parent)
Console.WriteLine("t5 dies " + Task.CurrentId.ToString())
waitFor5 = False
End Sub
Sub R(ByVal o As Object)
If (o = 2) Then
' wait for task5 to die
While waitFor5
End While
'//spin up all procs
Dim i As Integer
For i = 0 To pcount - 4 - 1
Dim t As Task = Task.Factory.StartNew(Sub()
While True
End While
End Sub)
Console.WriteLine("Started task " + t.Id.ToString())
Next
Task.Factory.StartNew(AddressOf T, i + 1 + 5, TaskCreationOptions.AttachedToParent) ' //scheduled
Task.Factory.StartNew(AddressOf T, i + 2 + 5, TaskCreationOptions.AttachedToParent) ' //scheduled
Task.Factory.StartNew(AddressOf T, i + 3 + 5, TaskCreationOptions.AttachedToParent) ' //scheduled
Task.Factory.StartNew(AddressOf T, i + 4 + 5, TaskCreationOptions.AttachedToParent) ' //scheduled
Task.Factory.StartNew(AddressOf 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(o = 4)
t3.Wait()
End If
End Sub
Sub T(ByVal o As Object)
Console.WriteLine("Scheduled run " + Task.CurrentId.ToString())
End Sub
Private t1, t2, t3, t4 As Task
Private aa As Integer = 0
Private bb As Integer = 0
Private cc As Integer = 0
Private waitFor1 As Boolean = True
Private waitFor5 As Boolean = True
Private pcount As Integer
Private mylock As New S2()
End Module
Public Class S2
End Class
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
class S
{
static void Main()
{
pcount = Environment.ProcessorCount;
Console.WriteLine("Proc count = " + pcount);
ThreadPool.SetMinThreads(4, -1);
ThreadPool.SetMaxThreads(4, -1);
t1 = new Task(A, 1);
t2 = new Task(A, 2);
t3 = new Task(A, 3);
t4 = new Task(A, 4);
Console.WriteLine("Starting t1 " + t1.Id.ToString());
t1.Start();
Console.WriteLine("Starting t2 " + t2.Id.ToString());
t2.Start();
Console.WriteLine("Starting t3 " + t3.Id.ToString());
t3.Start();
Console.WriteLine("Starting t4 " + t4.Id.ToString());
t4.Start();
Console.ReadLine();
}
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)
{
;
}
if (temp == 1)
{
// BP1 - all tasks in C
Debugger.Break();
waitFor1 = false;
}
else
{
while (waitFor1)
{
;
}
}
switch (temp)
{
case 1:
D(o);
break;
case 2:
F(o);
break;
case 3:
case 4:
I(o);
break;
default:
Debug.Assert(false, "fool");
break;
}
}
static void D(object o)
{
E(o);
}
static void E(object o)
{
// break here at the same time as H and K
while (bb < 2)
{
;
}
//BP2 - 1 in E, 2 in H, 3 in J, 4 in K
Debugger.Break();
Interlocked.Increment(ref bb);
//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();
}
#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <ppl.h>
#include <agents.h>
#include <stdio.h>
#include <concrtrm.h>
#include <vector>
CRITICAL_SECTION cs;
using namespace ::std;
using namespace ::std::tr1;
using namespace ::Concurrency;
task_group task4;
task_group task3;
task_group task2;
volatile long aa = 0;
volatile long bb = 0;
volatile long cc = 0;
static bool waitFor1 = true;
static bool waitFor5 = true;
#pragma optimize("", off)
void Spin()
{
for(int i=0;i<50*50000;++i);
}
#pragma optimize("",on)
template<class Func>
class RunFunc
{
Func& m_Func;
int m_o;
public:
RunFunc(Func func,int o):m_Func(func),m_o(o){
};
void operator()()const{
m_Func(m_o);
};
};
void T(int o)
{
cout << "Scheduled run \n";
};
void R(int o)
{
if (o == 2)
{
while (waitFor5) { ;}
Spin();
//use up all processors but 4 by scheduling 4 non-terminating tasks.
int numProcsToBurn = GetProcessorCount() - 4;
int i;
vector<call<int>*> tasks;
for (i = 0; i < numProcsToBurn; i++)
{
tasks.push_back(new call<int>([](int i){while(true)Spin();}));
asend(tasks[i],1);
cout << "Started task \n";
}
task_handle<RunFunc<decltype(T)>> t6(RunFunc<decltype(T)>(T,i + 1 + 5));
task_handle<RunFunc<decltype(T)>> t7(RunFunc<decltype(T)>(T,i + 2 + 5));
task_handle<RunFunc<decltype(T)>> t8(RunFunc<decltype(T)>(T,i + 3 + 5));
task_handle<RunFunc<decltype(T)>> t9(RunFunc<decltype(T)>(T,i + 4 + 5));
task_handle<RunFunc<decltype(T)>> t10(RunFunc<decltype(T)>(T,i + 5 + 5));
task2.run(t6);
task2.run(t7);
task2.run(t8);
task2.run(t9);
task2.run(t10);
//BP4 - 1 in M, 2 in R, 3 in J, 4 in R, 5 died
DebugBreak();
}
else
{
if (o!=4)
throw;
task3.wait();
}
};
void Q()
{
// breaks here at the same time as N and M
InterlockedIncrement(& cc);
while (cc < 4)
{
;
}
// task 5 dies here freeing task 4 (its parent)
cout << "t5 dies\n";
waitFor5 = false;
};
void P()
{
cout << "t5 runs\n";
Q();
};
void O(int o)
{
task_group t5;
t5.run(&P);
t5.wait();
R(o);
};
void N(int o)
{
// breaks here at the same time as M and Q
InterlockedIncrement(&cc);
while (cc < 4)
{
;
}
R(o);
};
void M(int o)
{
// breaks here at the same time as N and Q
InterlockedIncrement(&cc);
while (cc < 3)
{
;
}
//BP3 - 1 in M, 2 in N, 3 still in J, 4 in O, 5 in Q
DebugBreak();
InterlockedIncrement(&cc);
while (true)
Sleep(500); // for ever
};
void L(int oo)
{
int temp3 = oo;
switch (temp3)
{
case 1:
M(oo);
break;
case 2:
N(oo);
break;
case 4:
O(oo);
break;
default:
throw; //fool3
break;
}
}
void K(int o)
{
// break here at the same time as E and H
InterlockedIncrement(&bb);
EnterCriticalSection(&cs);
while (bb < 3)
{
;
}
LeaveCriticalSection(&cs);
Spin();
//after
L(o);
}
void J(int o)
{
int temp2 = o;
switch (temp2)
{
case 3:
task4.wait();
break;
case 4:
K(o);
break;
default:
throw; //fool2
break;
}
}
static void I(int o)
{
J(o);
}
static void H(int o)
{
// break here at the same time as E and K
InterlockedIncrement(&bb);
EnterCriticalSection(&cs);
while (bb < 3)
{
;
}
LeaveCriticalSection(&cs);
Spin();
//after
L(o);
}
static void G(int o)
{
H(o);
}
static void F(int o)
{
G(o);
}
static void E(int o)
{
// break here at the same time as H and K
while (bb < 2)
{
;
}
//BP2 - 1 in E, 2 in H, 3 in J, 4 in K
Spin(); // for native case only
DebugBreak();
InterlockedIncrement(&bb);
//after
L(o);
}
static void D(int o)
{
E(o);
}
static void C(int o)
{
int temp = o;
InterlockedIncrement(&aa);
while (aa < 4)
{
;
}
if (temp == 1)
{
// BP1 - all tasks in C
DebugBreak();
waitFor1 = false;
}
else
{
while (waitFor1)
{
;
}
}
switch (temp)
{
case 1:
D(o);
break;
case 2:
F(o);
break;
case 3:
case 4:
I(o);
break;
default:
throw; //fool
break;
}
}
static void B(int o)
{
C(o);
}
void A(int o)
{
B(o);
}
int main()
{
InitializeCriticalSection(&cs);
task_group tasks;
task_handle<RunFunc<decltype(A)>> t1(RunFunc<decltype(A)>(A,1));
tasks.run(t1);
task_handle<RunFunc<decltype(A)>> t2(RunFunc<decltype(A)>(A,2));
task2.run(t2);
task_handle<RunFunc<decltype(A)>> t3(RunFunc<decltype(A)>(A,3));
task3.run(t3);
task_handle<RunFunc<decltype(A)>> t4(RunFunc<decltype(A)>(A,4));
task4.run(t4);
getchar();
return 1;
}
No menu File, clique em Save All.
Sobre o Build menu, clique em Rebuild Solution.
Observe que há quatro chamadas para Debugger.Break (DebugBreak no exemplo de C++), portanto, você não precisará inserir pontos de interrupção; simplesmente executar o aplicativo fará com que ele falhe no depurador até quatro vezes.
Usando a janela de pilhas paralela: visualização de Threads
No menu Depuração, clique em Iniciar Depuração.Aguarde até que o primeiro ponto de interrupção sejam atingidos.
Para exibir a pilha de chamadas de um único thread
Sobre o Debug menu, aponte para Windows e, em seguida, clique em segmentos. Encaixe o segmentosjanela na parte inferior do Visual Studio.
Sobre o Debug menu, aponte para Windows e, em seguida, clique em Call Stack. Encaixe o Call Stackjanela na parte inferior Visual Studio.
Clique duas vezes em um thread a segmentosjanela para torná-lo atual. Segmentos atuais têm uma seta amarela.Quando você altera o threadatual, sua pilha de chamadas é exibido no Call Stackjanela.
Para examinar a pilhas paralela janela
Sobre o Debug menu, aponte para Windows e, em seguida, clique em Pilhas paralela. Certifique-se de que segmentos está selecionada na caixa no canto superior esquerdo.
Usando o Paralela pilhas janela, você pode exibir várias pilhas de chamadas ao mesmo tempo em uma exibição.A ilustração a seguir mostra a Paralela pilhas janela acima do Call Stackjanela.
pilha de chamadas do thread principal aparece em uma caixa e as pilhas de chamadas para outros quatro segmentos são agrupadas em outra caixa.Quatro segmentos são agrupados juntas, porque seus quadros de pilha compartilham os mesmo método contextos. ou seja, eles são nos mesmos métodos: A, B, e C.Para exibir os IDs de thread e os nomes dos threads que compartilham a mesma caixa, focalize o cabeçalho (4 segmentos).O thread atual é exibido em negrito, como mostrado na ilustração a seguir.
A seta amarela indica o quadro ativo de pilha do threadatual.Para obter mais informações, passe o mouse sobre ele
Você pode definir quantos detalhes para mostrar para os quadros de pilha (Nomes do módulo, Tipos de parâmetro, Nomes de parâmetro, Valores de parâmetro, Números de linha e Bytes desloca) clicando no Call Stackjanela.
Um realce azul ao redor de uma caixa indica que o thread atual faz parte do que a caixa.O thread atual também é indicado pelo quadro de pilha em negrito na dica de ferramenta.Se você clicar duas vezes o principal thread na janelaThreads, você poderá observar que o realce azul na Paralela pilhasjanela se move de acordo.
Para continuar a execução até que o segundo ponto de interrupção
Para continuar a execução até que o segundo ponto de interrupção é alcançado, diante do Depurar menu, clique em continuar. A ilustração a seguir mostra aárvore do threadno segundo ponto de interrupção.
No primeiro ponto de interrupção, todas as quatro segmentos de caiu de s. a para S.B para métodos S.C.Que informações ainda são visíveis no Paralela pilhasjanela, mas os quatro segmentos têm progrediu ainda mais. Um deles continua a S.D e, em seguida, SudesteOutro continuou a S.F, S.G e S.H.Dois outros continuação de S.I e S.J e há uma delas passou para S.K e o outro continua a aplicativos não - código dousuário externo.
Você pode focalizar caixa cabeçalho, por exemplo, 1 segmento ou 2 segmentos, para ver o thread IDs dos threads.Você pode focalizar os quadros de pilha para ver as identificações de thread além de outros detalhes do quadro .O realce azul indica o thread atual e a seta amarela indica o quadro ativo de pilha do threadatual.
O ícone de threads de tecido (azuis e vermelhos ondulado, linhas sobrepostas) indicam os quadros de pilha ativo dos threads não-circulantes.No Call Stackjanela, clique duas vezes em S.B para comutar estruturas. O Paralela pilhasjanela indica a pilha quadro atual do thread atual usando um ícone de seta curva verde.
No segmentos janela, alterna entre segmentos e observe que o modo de exibição a Paralela pilhasjanela é atualizada.
Você pode alternar para outro threadou para outro quadro de outro thread, usando omenu de atalhona Paralela pilhasjanela. Por exemplo, S.J com o botão direito, aponte para Switch para o quadroe, em seguida, clique em um comando.
S.C com o botão direito e aponte para Switch para o quadro.Um dos comandos possui uma marca de seleção indica o quadro de pilha do threadatual.Você pode alternar para o quadro do mesmo thread (moverá apenas na seta verde) ou você pode alternar para o outro thread (o realce azul também serão movidos).A ilustração a seguir mostra o submenu.
Quando um métododecontexto está associado a apenas uma pilha de quadro, a caixa cabeçalho exibe do Thread 1 e você pode alternar para ele clicando duas vezes. Se clicar duas vezes em umcontexto de métodoque tem mais de 1 quadro associado a ele, em seguida, no menu automaticamente surgirá. Quando você focaliza os contextos de método , observe o triângulo preto à direita.Clicar nesse triângulo também exibe omenude atalho.
Para aplicativos grandes que têm muitos segmentos, você poderá se concentrar em apenas um subconjunto de threads.O Paralela pilhasjanela pode exibir pilhas de chamadas somente para threads sinalizados. Na barra de ferramentas, clique no Mostrar sinalizado somente o botão próximo à caixa de listagem.
Em seguida, no segmentos janela, um por um, para ver a aparecem de suas pilhas de chamadas nos threads do sinalizar de Pilhas paralelajanela. Para segmentos de sinalizar , use omenu de atalhoou a primeira célula de um thread. Clique no Mostrar sinalizado somente botão de barra de ferramentas novamente para mostrar todos os threads.
Para continuar a execução até que o terceiro ponto de interrupção
Para continuar a execução até que o terceiro ponto de interrupção é alcançado, diante do Depurar menu, clique em continuar.
Quando vários segmentos estão no mesmo método , mas o método não estava no início da pilha de chamadas, o método aparece nas caixas diferentes.Um exemplo no ponto de interrupção atual é S.L, que tem três threads nele e aparece em três caixas.Clique duas vezes em S.L.
Observe que o S.L está em negrito nas duas caixas para que você possa ver onde mais poderia ser aparece.Se você quiser ver qual a chamada para S.L de quadros e quais quadros chamadas, clique no Alternar modo de exibição do método na barra de ferramentas.A ilustração a seguir mostra o modo de exibição do método a Paralela pilhas janela.
Observe como o diagrama dinamizado no método selecionado e posicionou na sua própria caixa no meio do modo de exibição.Os chamados e chamadores aparecem na parte superior e inferior.Clique no Alternar modo de exibição do método botão novamente para deixar esse modo.
Omenu de atalhoda Paralela pilhasjanela também tem os seguintes outros itens.
Exibição hexadecimal alterna os números nas dicas de ferramentas entre decimal e hexadecimal.
Informações de carga de símbolo e Configurações de símbolo em aberto as caixas de diálogo correspondente.
Go To Source Code e Go To Disassembly navegar no editor para o métodoselecionado.
Mostrar código externo exibe todos os quadros, mesmo que não estejam no código do usuário .Tente-lo para ver o diagrama expandir para acomodar os quadros adicionais (que podem ser esmaecidos porque você não tem símbolos para eles).
Quando você tem grandes diagramas e você passar para o próximo ponto de interrupção, é aconselhável o modo de exibição para a rolagem automática ao active pilha quadro do atual thread; ou seja, o thread que alcançou o ponto de interrupção pela primeira vez.No Pilhas paralela janela, certifique-se de que o A rolagem automática para o quadro de pilha atual botão na barra de ferramentas estiver em.
Antes de continuar, no Paralela pilhasjanela, todo o caminho para a esquerda e até o final de rolagem.
Para continuar a execução até que o quarto ponto de interrupção
Para continuar a execução até que o quarto ponto de interrupção é alcançado, diante do Depurar menu, clique em continuar.
Observe como o autoscrolled do modo de exibição no lugar.Alternar os threads na segmentos switch ou ajanela pilha de quadros a Call Stackjanela e observe como o modo de exibição sempre autoscrolls ao quadrocorreto. Desativar A rolagem automática para o quadro atual da ferramenta opção e ver a diferença.
O Exibição vista panorâmica também ajuda com grandes diagramas no Paralela pilhasjanela. Você pode ver o Exibição vista panorâmica , clicando no botão entre as barras de rolagem no canto inferior direito da janela, conforme mostrado na ilustração a seguir.
Você pode mover o retângulo para se deslocar rapidamente em torno do diagrama.
Outra maneira de mover o diagrama em qualquer direção é uma área vazia do diagrama de clique e arraste-a no local desejado.
Para aplicar zoom dentro e fora do diagrama, pressione e segure a tecla CTRL enquanto move a roda do mouse .Como alternativa, clique no botão Zoom na barra de ferramentas e, em seguida, use a ferramenta Zoom.
Você também pode visualizar as pilhas em uma direção de cima para baixo em vez de baixo para cima, clicando o Ferramentas menu, clique em Opçõese marque ou desmarque a opção sob o depuração nó.
Antes de continuar, diante do Depurar menu, clique em Stop Debugging execução final.
Usando a janela de tarefas paralelas e o modo de exibição de tarefas da janela pilhas paralela
É recomendável que você conclua os procedimentos anteriores antes de continuar.
Para reiniciar o aplicativo até o primeiro ponto de interrupção é atingido
Sobre o Debug menu, clique em Start Debugging e aguarde até que o primeiro ponto de interrupção sejam atingidos.
Sobre o Debug menu, aponte para Windows e, em seguida, clique em segmentos. Encaixe o segmentosjanela na parte inferior do Visual Studio.
Sobre o Debug menu, aponte para Windows e clique em Call Stack. Encaixe o Call Stackjanela na parte inferior Visual Studio.
Clique duas vezes em um thread a segmentosjanela para torna atual. Segmentos atuais têm a seta amarela.Quando você altera o threadatual, as outras janelas são atualizadas.Em seguida, examinaremos as tarefas.
Sobre o Debug menu, aponte para Windows e, em seguida, clique em Tarefas paralelas. A ilustração a seguir mostra a Tarefas paralelasjanela.
Para cada tarefa em execução, você pode ler a sua identificação, que é retornada pela propriedadede mesmo nome, o ID e o nome do thread que administra, sua localização (focalizando que exibe uma dica de ferramenta que possui a toda pilha de chamadas).Além disso, sob o tarefa coluna, você pode ver o método que foi passado para a tarefa; em outras palavras, o ponto de partida.
Você pode classificar qualquer coluna.Observe o glifo de classificação que indica a coluna de classificação e a direção.Você também pode reordenar as colunas arrastando-os para esquerda ou direita.
A seta amarela indica que a tarefaatual.Você pode alternar tarefas clicando duas vezes em uma tarefa ou usando omenude atalho. Quando você alternar tarefas, o thread de subjacente é atualizado e as outras janelas são atualizadas.
Quando você alterna manualmente de uma tarefa para outro, a seta amarela move, mas uma seta branca ainda mostra a tarefa que causou o depurador para quebrar.
Para continuar a execução até que o segundo ponto de interrupção
Para continuar a execução até que o segundo ponto de interrupção é alcançado, diante do Depurar menu, clique em continuar.
Anteriormente, o Status coluna mostrou todas as tarefas como execução, mas agora duas tarefas estão aguardando.As tarefas podem ser bloqueadas por diversos motivos.No Status coluna, passe o mouse sobre uma tarefa de espera para saber por que ele está bloqueado.Por exemplo, na ilustração a seguir, a tarefa 3 está aguardando a tarefa 4.
Tarefa 4, por sua vez, está aguardando um monitor do thread atribuído à tarefa 2.
Você pode sinalizar uma tarefa clicando-se o sinalizar na primeira coluna da Tarefas paralelasjanela.
Você pode usar a sinalização para controlar as tarefas entre diferentes pontos de interrupção na mesma sessão de depuração ou filtrar as tarefas cujas pilhas de chamadas são mostradas na Paralela pilhasjanela.
Quando foi usado o Pilhas paralelajanela anterior, que foram exibidos os threads do aplicativo . Modo de exibição de Pilhas paralelajanela novamente, mas desta vez exibir as tarefas de aplicativo . Fazer isso selecionando tarefas na caixa no canto superior esquerdo.A ilustração a seguir mostra o modo de exibição de tarefas.
Threads que não estão em execução tarefas não são mostrados na exibição de tarefas do Paralela pilhasjanela. Além disso, para os threads que executar tarefas, alguns dos quadros de pilha que não sejam relevantes para as tarefas são filtradas superior e inferior da pilha.
Modo de exibição de Tarefas paralelasjanela novamente. Clique com o botão direito qualquer cabeçalho de coluna para ver ummenu de atalhopara a coluna.
Você pode usar omenu de atalhopara adicionar ou remover colunas. Por exemplo, a coluna de AppDomain não está selecionada; Portanto, não é exibido na lista.Clique em pai.O pai coluna aparece sem valores para qualquer uma das quatro tarefas.
Para continuar a execução até que o terceiro ponto de interrupção
Para continuar a execução até que o terceiro ponto de interrupção é alcançado, diante do Depurar menu, clique em continuar.
Uma nova tarefa, tarefa 5, agora está sendo executado e está aguardando a tarefa 4.Você pode ver por que passando sobre a tarefa de espera na Statusjanela. No pai coluna, observe que a tarefa 4 é o pai da tarefa 5.
Para visualizar melhor a pai -filhorelação, clique com o botão direito do pai cabeçalho da coluna e clique Exibição pai-filho. Você deverá ver a ilustração a seguir.
Observe que a tarefa 4 e a tarefa 5 estão sendo executados no mesmo thread.Essas informações não são exibidas no segmentosjanela; vê-lo aqui é outro benefício da Tarefas paralelasjanela. Para confirmar isso, exiba o Paralela pilhasjanela. Certifique-se de que você está exibindo tarefas.Localize as tarefas de 4 e 5 clicando duas vezes na Tarefas paralelasjanela. Quando você faz, o realce azul no Paralela pilhasjanela é atualizada. Também é possível localizar tarefas 4 e 5, examinando as dicas de ferramentas na Paralela pilhasjanela.
No Paralela pilhas janela, clique com o botão direito p e, em seguida, clique em Ir para Thread. A janela alterna para o modo de Threads e o quadro correspondente está no modo de exibição.Você pode ver ambas as tarefas no mesmo thread.
Este é outro benefício do modo de exibição de tarefas no Paralela pilhas janela, em comparação comparada o segmentosjanela.
Para continuar a execução até que o quarto ponto de interrupção
Para continuar a execução até que o terceiro ponto de interrupção é alcançado, diante do Depurar menu, clique em continuar. Clique no ID cabeçalho da coluna para classificar por ID.Você deverá ver a ilustração a seguir.
Porque concluiu a tarefa 5, ele não é mais exibido.Se não for o maiúsculas e minúsculas em seu computador e o deadlock não é mostrada, passo uma vez pressionando F11.
Tarefa 3 e a tarefa 4 agora estão aguardando uns dos outros e estão bloqueadas.Também existem 5 novas tarefas que são filhos de tarefa 2 e agora estão programadas.Tarefas agendadas são tarefas que foram iniciadas no código, mas ainda não o executaram.Portanto, suas local e A atribuição de segmento colunas estão vazias.
Exibir o Paralela pilhasjanela novamente. O cabeçalho de cada caixa tem uma dica de ferramenta que mostra os nomes e identificações de thread .Alterne para modo de exibição de tarefas no Paralela pilhasjanela. Passe o mouse sobre um cabeçalho para ver a ID da tarefa e o nome e o status da tarefa, conforme mostrado na ilustração a seguir.
Você pode grupo as tarefas por coluna.No Tarefas paralelas janela, com o botão direito do Status cabeçalho da coluna e clique Agrupar por Status. A ilustração a seguir mostra a Tarefas paralelasjanela agrupados por status.
Você também pode grupo por qualquer outra coluna.Agrupar tarefas, você pode focalizar um subconjunto de tarefas.Cada grupo de recolhível tem uma contagem dos itens que estão agrupadas juntas.Você pode também rapidamente sinalizar todos os itens do grupo clicando o Sinalizador o botão à direita da Recolher botão.
O último recurso da Tarefas paralelasjanela para examinar é omenu de atalhoque é exibido quando o botão direito do mouse uma tarefa.
Omenu de atalhoexibe comandos diferentes, dependendo do status da tarefa. Os comandos podem incluir Copy, Selecionar tudo, Exibição Hexadecimal, Switch a tarefa, Congelar atribuído Thread, Congelar todos os Threads, mas este, e Descongelar atribuído Thread, e Sinalizador.
Você pode congelar o thread subjacente de uma tarefaou tarefas, ou poderá congelar todos os threads, exceto aquele atribuído.Um thread de congelados é representado no Tarefas paralelas janela como ela está na segmentos janela, por um azul Pausar ícone.
Resumo
Esta explicação passo a passo demonstrou a Tarefas paralelas e Paralela pilhas o depurador de janelas.Use essas janelas em projetos reais que usam o código multithread.Você pode examinar o código paralelo escrito em C++, C# ou Visual Basic.
Consulte também
Tarefas
Passo a passo: Depurando um aplicativo paralelo
Conceitos
Tempo de execução de concorrência
Usando a janela de pilhas paralela
Usando a janela de tarefas paralelas