Udostępnij za pośrednictwem


Instruktaż: Debugowanie aplikacji równoległe

W tym instruktażu przedstawiono sposób użycia Zadania równolegle i Równolegle stosy systemu windows do debugować aplikacji równolegle.Okna te ułatwić zrozumienie i sprawdzić działanie runtime kod, który używa Zadanie równoległe biblioteki (TPL) lub Współbieżność Runtime.Ten instruktaż zawiera przykładowy kod, który ma wbudowane punkty przerwania.Po podziały wierszy kodu, instruktaż ilustruje sposób użycia Zadania równolegle i Równolegle stosy systemu windows do zbadania jej.

W tym instruktażu uczy tych zadań:

  • Jak wyświetlić stosy wywołań wszystkich wątków w jednym widoku.

  • Jak wyświetlić listę System.Threading.Tasks.Task wystąpień, które są tworzone w aplikacji.

  • Jak wyświetlić stosy wywołań rzeczywiste zadań zamiast wątków.

  • Jak przechodzenie do kodu z Zadania równolegle i Równolegle stosy systemu windows.

  • Jak windows radzenia sobie ze skalą poprzez grupowanie, powiększanie i inne funkcje pokrewne.

Wymagania wstępne

W tym instruktażu zakłada się, że Just Mój kod jest włączone.Na Narzędzia menu, kliknij Opcje, rozwiń węzeł Debugowanie węzła, zaznacz Ogólne, a następnie wybierz włączyć tylko Mój kod (tylko zarządzane). Jeśli ta cechanie jest ustawiona, można nadal używać w tym instruktażu, ale wyniki mogą różnić się od ilustracji.

C# próbki

Użycie języka C# próbki, w tym instruktażu założono również, że kod zewnętrzny jest ukryty.Aby przełączyć czy kod zewnętrzny jest wyświetlany, kliknij prawym przyciskiem myszy Nazwa tabeli nagłówek Stos okno, a następnie wybierz lub wyczyść Pokaż kod zewnętrzny. Jeśli ta cechanie jest ustawiona, można nadal używać w tym instruktażu, ale wyniki mogą różnić się od ilustracji.

Próbki C++

Jeśli używasz próbki C++, można zignorować odniesienia do zewnętrznego kodu w tym temacie.Kod zewnętrzny dotyczy tylko próbkę C#.

Ilustracje

Ilustracje, w tym temacie są rejestrowane na komputerze czterordzeniowe z próbki C#.Chociaż można użyć innych konfiguracji do przeprowadzenia tego instruktażu, ilustracji może różnić się od wyświetlanego na komputerze.

Tworzenie projektu próbki

Kod przykładowy, w tym instruktażu jest dla aplikacji, która nie wykonuje żadnej operacji.cel jest po prostu zrozumienie sposobu korzystania z systemu windows narzędzie do debugować aplikacji równolegle.

Aby utworzyć przykładowy projekt

  1. W Visual Studiona pliku menu, wskaż Nowy , a następnie kliknij przycisk Projekt.

  2. W Zainstalowane szablonyokienko, zaznacz albo Visual C#, Visual Basiclub Visual C++. Dla języków zarządzanych, zapewnić, że .NET Framework 4 jest wyświetlany w polu ramy.

  3. Wybierz Console Application , a następnie kliknij przycisk OK.Pozostają w konfiguracjadebugowania, co jest ustawieniem domyślnym.

  4. Otwórz plik kodu .cpp, .cs lub .vb w projekt.Usunąć jego zawartość, aby utworzyć plik kod pusty.

  5. Wklej następujący kod dla wybranego języka do pliku kod pusty.

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;
}
  1. Na pliku menu, kliknij przycisk Zapisz wszystkie.

  2. Na budować menu, kliknij przycisk Roztwór odbudować.

    Są cztery wywołania Debugger.Break (DebugBreak w próbce C++) w związku z tym, nie trzeba wstawiać punkty przerwania; tylko z uruchomioną aplikacją spowoduje zerwanie w debugerze maksymalnie cztery razy.

Za pomocą okna stosy równoległego: Widok wątków

Na debugowania menu, kliknij przycisk Start Debugging. Poczekaj, aż pierwszy punkt przerwania można trafić.

Aby wyświetlić pojedynczy wątek stos wywołań

  1. Na debugowania menu, wskaż Windows , a następnie kliknij przycisk wątków. Zadokuj wątkówokno u dołu Visual Studio.

  2. Na debugowania menu, wskaż Windows , a następnie kliknij przycisk Stos. Zadokuj Stosokno u dołu Visual Studio.

  3. Kliknij dwukrotnie ikonę wątek w wątkówokno , aby bieżący. Bieżące wątki posiadają żółta strzałka.Po zmianie bieżącego wątekjej stos wywołań jest wyświetlany w Stosokno.

Do zbadania równoległych stosy okno

  • Na debugowania menu, wskaż Windows , a następnie kliknij przycisk Równolegle stosy. Upewnij się, że wątków jest zaznaczona w polu znajdującym się w lewym górnym rogu.

    Za pomocą Równolegle stosy okno, można wyświetlić wiele stosy wywołań, w tym samym czasie w jednym widoku.Na poniższej ilustracji pokazano Równolegle stosy okno powyżej Stosokno.

    Okno stosów równoległych w widoku wątków

    stos wywołań wątek głównego pojawi się w jednym polu i stosy wywołań dla cztery wątki są zgrupowane w innym polu.Cztery wątki są grupowane razem, ponieważ ich ramek stosu używają tej samej kontekstów metoda ; oznacza to, że są one w tej samej metody: A, B, i C.Widok wątek identyfikatory i nazwy wątków, które współużytkują ten sam pole, przesuń kursor nad nagłówek (4 wątki).Bieżący wątek jest wyświetlana w pogrubienie, jak pokazano na poniższej ilustracji.

    Etykietka narzędzia z nazwy i identyfikatory wątków

    Żółta strzałka wskazuje aktywny stosu ramka bieżącego wątek.Aby uzyskać więcej informacji, przemieść nad nim wskaźnik

    Wskazówka ramek stosu active

    Można ustawić ilość szczegółów, aby pokazać ramek stosu (Nazwy modułu, Typy parametrów, Nazwy parametru, Wartości parametrów, Numery linii i Bajt jest przeciwstawna) przez kliknięcie prawym przyciskiem myszy, w Stosokno.

    Niebieski podświetlenia wokół pola wskazuje, że bieżący wątek jest częścią tego pola.Bieżący wątek jest również wskazywane przez pogrubienie stosu ramka w etykietce narzędzia.Jeśli klikniesz dwukrotnie głównego wątek w wątki okno, można zaobserwować, że niebieskie podświetlenie w Stosy równolegleokno porusza się odpowiednio.

    Stosy z głównego wątku wyróżnione kolorem niebieskim

Aby wznowić wykonywanie aż do drugiego punkt przerwania

  • Wznowienie wykonywania, dopóki drugi punkt przerwania jest hit, z debugowania menu, kliknij przycisk Kontynuuj. Na następującej ilustracji pokazano wątek drzewo na drugi punkt przerwania.

    Okno stosów równoległych w wieloma rozgałęzieniami

    Na pierwszy punkt przerwaniawszystkie cztery wątki wzrósł od S.A do S.B do metody S.C.Że informacje są nadal widoczne w Równolegle stosyokno, ale cztery wątki postępują dalszych. Jeden z nich nadal S.D, a następnie S.E.Inny nadal S.F, S.G i S.H.Dwa inne nadal S.I i S.J oraz z nim jedno z nich udał się do S.K i kontynuowane drugiej do innych niż - kod zewnętrznyużytkownik .

    Można na przykład wskaźnik nad pole nagłówek, 1 wątek lub 2 wątki, aby zobaczyć wątek identyfikatory wątków.Można Aktywuj ramek stosu, aby zobaczyć identyfikatory wątek , plus inne szczegóły ramka .Wyróżnij niebieskie wskazuje bieżący wątek i żółta strzałka wskazuje aktywny stosu ramka bieżącego wątek.

    Ikona szmatką wątków (nakładających się niebieski i czerwony waved linie) wskazują ramek stosu aktywnych wątków, inne niż bieżące.W Stosokno, kliknij dwukrotnie S.B, aby przełączyć ramek. Równolegle stosyokno wskazuje bieżącą stosu ramka z bieżącego wątek za pomocą ikony zieloną strzałkę zakrzywioną.

    W wątków oknoprzełączyć się pomiędzy wątkami i że widoku w Równolegle stosyokno jest aktualizowany.

    Można przełączyć do innego wąteklub do innej ramka inny wątekprzy użyciumenu skrótw Równolegle stosyokno. Na przykład, kliknij prawym przyciskiem myszy S.J, wskaż polecenie Przełącznika do ramki, a następnie kliknij odpowiednie polecenie.

    Ścieżka stosów równoległych z wykonania

    Kliknij prawym przyciskiem myszy S.C, a następnie wskaż polecenie Przełącznika do ramki.Jedno z poleceń ma znacznik wyboru wskazuje stosu ramka z bieżącego wątek.Przełącz się do tej ramka w tym samym wątek (tylko zielona strzałka spowoduje przeniesienie) lub przełączyć się do innego wątek (niebieski zostanie również zaznaczony).Na następującej ilustracji pokazano podmenu.

    Menu stosów opcje 2 C, podczas gdy J jest aktualny

    Gdy metodakontekst jest skojarzony z stos tylko jedną ramka, pole nagłówek Wyświetla 1 wątku i nastąpi przełączenie do niego przez dwukrotne kliknięcie. Jeśli klikniesz dwukrotnie metoda kontekst , który ma więcej niż 1 ramka skojarzony z nim, następnie w menu automatycznie pojawia się.Jako wskaźnik nad kontekstów metoda , należy zauważyć, czarny trójkąt po prawej stronie.Również kliknięcie tym trójkąt Wyświetlamenu skrót.

    Dla dużych aplikacji, które mają wiele wątków chcesz skupić się na ich podzbiór wątków.Równolegle stosymożna wyświetlić wokno stosy wywołań tylko dla wątków oznaczone flagami. Na pasku narzędzi kliknij przycisk Pokaż tylko oflagowane przycisk Dalej, aby pole listy.

    Puste okno stosów i etykietki narzędzia

    W następnej wątków okno oflagować wątki jeden po drugim, aby zobaczyć, jak ich stosy wywołań pojawiają się w Równolegle stosyokno. oflagować wątków użyjmenu skrótlub pierwszą komórkę wątek. Kliknij przycisk Pokaż tylko oflagowane przycisk paska narzędzi ponownie, aby wyświetlić wszystkie wątki.

Aby wznowić wykonywanie aż do trzeciego punkt przerwania

  1. Wznowienie wykonywania, dopóki trzeci punkt przerwania jest hit, z debugowania menu, kliknij przycisk Kontynuuj.

    Gdy wiele wątków są w tej samej metoda , ale metoda nie był na początku stos wywołań, metoda pojawia się w różnych polach.Przykładem na bieżący punkt przerwania jest S.L, który ma trzy wątki i pojawia się w trzech polach.Kliknij dwukrotnie S.L.

    Ścieżka wykonywania stosów równoległych

    Należy zauważyć, że S.L jest pogrubiony w innych polach, dzięki czemu można zobaczyć, gdzie indziej pojawia się.Jeśli chcesz zobaczyć które ramki wywołanie do S.L i które ramki go wywołania, kliknij przycisk Przełącz widok metoda przycisku na pasku narzędzi.Na następującej ilustracji pokazano widok metoda Równolegle stosy okno.

    Okno stosów w widoku metod

    Należy zauważyć, jak diagram przestawiany na wybranej metoda i on umieszczony w jego własne pole w środku widoku.Zapobieganie i wywoływania są wyświetlane na górze i na dole.Kliknij przycisk Przełącz widok metoda przycisk ponownie, aby opuścić ten tryb.

    Wmenu skrótz Równolegle stosyokno zawiera również następujące inne elementy.

    • Wyświetlanie szesnastkowych przełącza numery w etykietkach narzędzi między liczba dziesiętna i szesnastkowo.

    • Symbol informacji obciążenia i Ustawienia Symbol otwarty odpowiednich oknach dialogowych.

    • Przejdź do kodu źródłowego i Go do demontażu nawigowanie w edytor wybranej metoda.

    • Pokaż kod zewnętrzny Wyświetla wszystkie ramki, nawet jeśli nie są w kodzie użytkownik .Spróbuj wyświetlić diagram, rozwiń, aby pomieścić dodatkowe ramki, (które mogą być nieaktywne, ponieważ nie masz symbole dla nich).

    Gdy masz dużych diagramów i kroku do następnego punkt przerwania, może być w celu automatycznego przewijania do stosu active ramka bieżącego wątek; oznacza to, że wątek , który pierwszy hit punkt przerwania .W Równolegle stosy okno, upewnij się, że Autoprzewijanie do bieżącej klatki stosu znajduje się na przycisku na pasku narzędzi.

    Niewygodną Okno stosów równoległych

  2. Zanim będziesz kontynuować, w Równolegle stosyokno, przewijania wszystkich sposób, w lewo i w dół do końca.

Aby wznowić wykonywanie aż do czwartego punkt przerwania

  1. Wznowienie wykonywania, dopóki czwarty punkt przerwania jest hit, z debugowania menu, kliknij przycisk Kontynuuj.

    Zawiadomienie jak autoscrolled widok na miejscu.Przełączanie wątków w wątków stosuokno lub przełącznik ramki w Stosokno i ogłoszenia jak widok zawsze autoscrolls do poprawnej ramka. Wyłącz Autoprzewijanie do bieżącej klatki narzędzie opcji i umożliwia wyświetlanie różnicy.

    Widok z lotu ptaka również pomaga w dużych diagramów w Równolegle stosyokno. Można zobaczyć Widok z lotu ptaka przez kliknięcie przycisku między paskami przewijania w prawym dolnym rogu okno, jak pokazano na poniższej ilustracji.

    Okno stosów równoległych z lotu ptaka

    Można przenieść prostokąt, szybkie przesuwanie na diagramie.

    Przenoszenie diagramu w dowolnym kierunku w inny sposób jest kliknij pusty obszar na diagramie i przeciągnij go w wybrane miejsce.

    powiększyć z diagramu naciśnij i przytrzymaj klawisz CTRL podczas przenoszenia kółko mysz .Alternatywnie kliknij przycisk powiększenia na pasku narzędzi, a następnie użyj narzędzia Lupka.

    Stosy obok siebie na powiększony

    Można również wyświetlić stosy w kierunku góra dół, zamiast w dół góra, klikając Narzędzia menu, klikając polecenie Opcje, a następnie zaznacz lub wyczyść opcję w obszarze Debugowanie węzła.

  2. Przed rozpoczęciem pracy z debugowania menu, kliknij przycisk Stop Debugging do realizacji celu.

Przy użyciu okna zadania równolegle i widoku zadania równolegle stosy okno

Zaleca się, aby zakończyć procedury wcześniej, przed kontynuowaniem.

Hit jest ponowne uruchomienie aplikacji aż do pierwszego punkt przerwania

  1. Na debugowania menu, kliknij przycisk Start Debugging i czeka na pierwszy punkt przerwania można trafić.

  2. Na debugowania menu, wskaż Windows , a następnie kliknij przycisk wątków. Zadokuj wątkówokno u dołu Visual Studio.

  3. Na debugowania menu, wskaż Windows i kliknij przycisk Stos. Zadokuj Stosokno u dołu Visual Studio.

  4. Kliknij dwukrotnie ikonę wątek w wątkówokno czyni bieżącego. Bieżące wątki posiadają żółta strzałka.Po zmianie bieżącego wątekinne okna są aktualizowane.Następnie będziemy sprawdzać zadań.

  5. Na debugowania menu, wskaż Windows , a następnie kliknij przycisk Zadania równolegle. Na poniższej ilustracji pokazano Zadania równolegleokno.

    Okno zadań równoległych z 4 uruchomionych zadań

    Dla każdego działającego zadania można odczytać Identyfikatora, który jest zwracany przez właściwośćo tej samej nazwie, identyfikator i nazwę wątek , który jest uruchamiany, jego lokalizację (najechanie ten wyświetla etykietka, która ma cały stos wywołań).Ponadto, w obszarze zadania kolumny, można wyświetlić metoda przekazano zadania; innymi słowy punkt początkowy.

    Można sortować dowolnej kolumny.Zawiadomienie sortowania symbol , który wskazuje sortowanie kolumn i kierunek.Można również zmienić kolejność kolumn, przeciągając je w lewo lub w prawo.

    Żółta strzałka wskazuje bieżące zadanie.Zadania można przełączać, klikając dwukrotnie ikonę zadania lub za pomocąmenu skrót. Podczas przełączania zadań podstawowej wątek staje się bieżącym i inne okna są aktualizowane.

    Gdy ręcznie przełączać się z jednego zadania do innego, żółta strzałka przemieszcza się białej strzałki nadal pokazuje zadania, który spowodował debugera przerwać.

Aby wznowić wykonywanie aż do drugiego punkt przerwania

  • Wznowienie wykonywania, dopóki drugi punkt przerwania jest hit, z debugowania menu, kliknij przycisk Kontynuuj.

    Wcześniej stanu kolumny wykazało, jak uruchamianie wszystkich zadań, ale teraz dwóch zadań oczekujących.Zadania mogą być blokowane dla wielu różnych powodów.W stanu kolumny, aktywowania za pośrednictwem zadań oczekujących, aby dowiedzieć się, dlaczego jest ono blokowane.Na przykład na poniższej ilustracji, zadanie 3 jest oczekiwanie na zadanie 4.

    Okno zadań równoległych z dwoma oczekującymi zadaniami

    Zadanie 4, z kolei jest oczekiwanie na monitorze, posiadane przez wątek przydzielony do zadania 2.

    Okienko zadań z zadań oczekujących i etykietki narzędzia

    Można zadanie oflagować klikając w pierwszej kolumnie oflagować Zadania równolegleokno.

    Flagi monitujące – można użyć do śledzenia zadań między różne punkty przerwania w tej samej sesji debugowanie lub filtr zadań, których stosy wywołań są wyświetlane w Równolegle stosyokno.

    Kiedy używane Równolegle stosyokno wcześniej, przeglądać wątki aplikacji. Widok Równolegle stosyokno ponownie, ale tym razem wyświetlanie zadań aplikacji. To zrobić, zaznaczając zadania w polu w lewym górnym rogu.Następująca ilustracja pokazuje widok zadań.

    Okno zadań równoległych w widoku zadania

    Wątki, które nie są aktualnie wykonywanych zadań nie są wyświetlane w widoku zadania z Równolegle stosyokno. Ponadto w przypadku wątków, że wykonać zadania niektórych ramek stosu, które nie są odpowiednie do zadań są filtrowane z góry i u dołu stosu.

    Widok Zadania równolegleponownieokno . Kliknij prawym przyciskiem myszy dowolny nagłówek kolumny aby wyświetlićmenu skrótdla kolumny.

    Menu równoległy columnheader zadań

    Aby dodać lub usunąć kolumny, można użyćmenu skrót. Na przykład kolumna domena aplikacji nie została wybrana; w związku z tym nie jest wyświetlany na liście.Kliknij przycisk nadrzędnej.Nadrzędnej kolumna jest wyświetlana bez wartości dla każdego z czterech zadań.

Aby wznowić wykonywanie aż do trzeciego punkt przerwania

  • Wznowienie wykonywania, dopóki trzeci punkt przerwania jest hit, z debugowania menu, kliknij przycisk Kontynuuj.

    Nowe zadanie zadania 5, obecnie jest uruchomiony i obecnie oczekuje zadanie 4.Można zobaczyć, dlaczego poprzez najechanie wskaźnikiem zadań oczekujących w stanuokno. W nadrzędnej kolumny, zawiadomienie to zadanie 4 jest nadrzędny zadanie 5.

    Aby lepiej uświadomić sobieelement podrzędnynadrzędny -relacja, kliknij prawym przyciskiem myszy nadrzędnej kolumna, nagłówek , a następnie kliknij przycisk Widok podrzędny nadrzędnej. Następująca ilustracja powinny być widoczne.

    Widok równoległy zadań w widoku podrzędnego nadrzędnego

    Należy zauważyć, że zadanie 4 i 5 zadania są uruchomione na tym samym wątek.Te informacje nie są wyświetlane w wątkówokno; zobaczenie go tutaj jest inną korzyścią płynącą z Zadania równolegleokno. Można to potwierdzić, wyświetlić Równolegle stosyokno. Upewnij się, że oglądasz zadania.Znajdź zadania, 4 i 5 przez dwukrotne kliknięcie pliku w Zadania równolegleokno. Powoduje to podświetlenie niebieski Równolegle stosyokno jest aktualizowany. Możesz również znaleźć zadania, 4 i 5, skanując etykietki narzędzi na Równolegle stosyokno.

    Okno stosów równoległych w widoku zadania

    W Równolegle stosy okno, kliknij prawym przyciskiem myszy S.P, a następnie kliknij przycisk Go do wątku. W okno przełącza na widok wątków i odpowiadające im ramka jest w widoku.W tym samym wątek, można wyświetlić oba zadania.

    Widok wątków z wątkiem wyróżnione

    Jest to korzyść innego widoku zadań, w Równolegle stosy okno, w porównaniu do wątkówokno.

Aby wznowić wykonywanie aż do czwartego punkt przerwania

  • Wznowienie wykonywania, dopóki trzeci punkt przerwania jest hit, z debugowania menu, kliknij przycisk Kontynuuj. Kliknij przycisk ID nagłówek kolumny, aby posortować według identyfikatora.Następująca ilustracja powinny być widoczne.

    Okno stosów równoległych z zadaniami w czterech stanach

    Ponieważ zadanie 5 zostało ukończone, jest już wyświetlany.Jeśli nie jest to przypadek na komputerze i zakleszczenie nie jest widoczne, krok jeden raz, naciskając klawisz F11.

    Zadanie 3 i 4 zadań teraz trwa oczekiwanie na siebie i są zakleszczone.Istnieją również 5 nowych zadań, które są dzieci 2 zadania i są obecnie zaplanowane.Zaplanowane zadania są zadania, które zostały rozpoczęte w kodzie, ale nie zostały jeszcze uruchomiony.W związku z tym ich lokalizację i Przydziału wątku kolumny są puste.

    Widok Równolegle stosyponownieokno . nagłówek każde pole ma etykietce narzędzia, która zawiera identyfikatory wątek i nazwy.Przełącz się do widoku zadań w Równolegle stosyokno. Aktywuj nagłówek , aby zobaczyć identyfikator zadania oraz nazwę i stan zadania, jak pokazano na poniższej ilustracji.

    Okno stosów równoległych z etykietką narzędzia dotyczącą nagłówka

    Możesz grupa zadań według kolumny.W Zadania równolegle okno, kliknij prawym przyciskiem myszy stanu kolumna, nagłówek , a następnie kliknij przycisk grupy według stanu. Na poniższej ilustracji pokazano Zadania równolegleokno pogrupowane według stan.

    Okno zadań równoległych z zadaniami zgrupowane

    Można również grupa przez inną kolumnę.Grupowanie zadań możesz skupić podzbiór zadań.Każda zwijany grupa ma liczba elementów, które są zgrupowane razem.Można również szybko oflagować wszystkich elementów w grupa klikając Flaga przycisk po prawej stronie Zwiń przycisku.

    Okno zadań równoległych zgrupowane

    Ostatnia cecha z Zadania równolegleokno , aby zbadać jestmenu skrót, wyświetlanego po kliknięciu zadania prawym przyciskiem myszy.

    Równoległe contextmenu okno zadań rozszerzony

    skrótmenu wyświetla różne polecenia, w zależności od stan zadania. Polecenia mogą zawierać kopię, Zaznacz wszystko, Wyświetlanie szesnastkowych, przełącznik do zadania, Zamrozić przypisane wątku, Zablokować wszystkie wątki, ale ten, i Rozmrażanie przypisane wątku, i Flaga.

    Można blokować podstawowej wątek lub zadania, lub można blokować wszystkie wątki, z wyjątkiem przypisany jeden.Mrożone wątek jest reprezentowana w Zadania równolegle okno jak to jest w wątków okno, Blue wstrzymać ikona.

Podsumowanie

Wykazane w tym instruktażu Zadania równolegle i Równolegle stosy debuger systemu windows.Użyj tych okien na rzeczywistych projektów korzystających wielowątkowe kodu.Można sprawdzić równoległych kod napisany w C++, C# lub Visual Basic.

Zobacz też

Zadania

Instruktaż: Debugowanie aplikacji równoległe

Koncepcje

Współbieżność Runtime

Za pomocą okna stosy równoległe

Przy użyciu okna zadania równolegle

Inne zasoby

Mapa drogowa debugera

Debugowanie kodu zarządzanego

Programowanie w równoległe.NET Framework