다중 스레드 애플리케이션 디버깅 시작(C#, Visual Basic, C++)

Visual Studio는 다중 스레드 애플리케이션을 디버그하는 데 도움이 되는 여러 도구와 사용자 인터페이스 요소를 제공합니다. 이 자습서에서는 스레드 마커, 병렬 스택 창, 병렬 조사식 창, 조건부 중단점 및 필터 중단점을 사용하는 방법을 보여줍니다. 이 자습서를 완료하면 다중 스레드 애플리케이션을 디버깅하는 Visual Studio 기능을 익힐 수 있습니다.

다음 두 문서에서는 다른 다중 스레드 디버깅 도구 사용에 대한 추가 정보를 제공합니다.

첫 번째 단계에서는 다중 스레드 애플리케이션 프로젝트를 만듭니다.

다중 스레드 앱 프로젝트 만들기

  1. Visual Studio를 연 다음 새 프로젝트를 만듭니다.

    시작 창이 열려 있지 않으면 파일>시작 창을 선택합니다.

    시작 창에서 새 프로젝트 만들기를 선택합니다.

    새 프로젝트 만들기 창에서 검색 상자에 콘솔을 입력합니다. 다음으로, 언어 목록에서 C#, C++ 또는 Visual Basic을 선택한 다음, 플랫폼 목록에서 Windows를 선택합니다.

    언어 및 플랫폼 필터를 적용한 후 .NET 또는 C++용 콘솔 앱 템플릿을 선택한 후, 다음을 선택합니다.

    참고 항목

    올바른 템플릿이 표시되지 않으면 도구>도구 및 기능 가져오기...로 이동합니다. 그러면 Visual Studio 설치 관리자가 열립니다. .NET 데스크톱 개발 또는 C++를 사용한 데스크톱 개발 워크로드를 선택한 다음, 수정을 선택합니다.

    새 프로젝트 구성 창의 프로젝트 이름 상자에 MyThreadWalkthroughApp을 입력합니다. 그런 다음, 다음 또는 만들기 중 사용 가능한 옵션 하나를 선택합니다.

    .NET Core 또는 .NET 5+ 프로젝트에서 권장되는 대상 프레임워크 또는 .NET 8을 선택한 후 만들기를 선택합니다.

    새 콘솔 프로젝트가 나타납니다. 프로젝트가 만들어지면 소스 파일이 나타납니다. 선택한 언어에 따라 소스 파일 이름이 Program.cs, MyThreadWalkthroughApp.cpp 또는 Module1.vb입니다.

  2. 소스 파일에 표시되는 코드를 삭제하고 업데이트된 다음 코드로 바꿉니다. 코드 구성에 적절한 코드 조각을 선택합니다.

    using System;
    using System.Threading;
    
    public class ServerClass
    {
    
        static int count = 0;
        // The method that will be called when the thread is started.
        public void InstanceMethod()
        {
            Console.WriteLine(
                "ServerClass.InstanceMethod is running on another thread.");
    
            int data = count++;
            // Pause for a moment to provide a delay to make
            // threads more apparent.
            Thread.Sleep(3000);
            Console.WriteLine(
                "The instance method called by the worker thread has ended. " + data);
        }
    }
    
    public class Simple
    {
        public static void Main()
        {
            for (int i = 0; i < 10; i++)
            {
                CreateThreads();
            }
        }
        public static void CreateThreads()
        {
            ServerClass serverObject = new ServerClass();
    
            Thread InstanceCaller = new Thread(new ThreadStart(serverObject.InstanceMethod));
            // Start the thread.
            InstanceCaller.Start();
    
            Console.WriteLine("The Main() thread calls this after "
                + "starting the new InstanceCaller thread.");
    
        }
    }
    
  3. 파일 메뉴에서 모두 저장을 선택합니다.

  4. (Visual Basic만 해당) 솔루션 탐색기(오른쪽 창)에서 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 애플리케이션 탭에서 시작 개체단순으로 변경합니다.

다중 스레드 앱 디버그

  1. 소스 코드 편집기에서 다음 코드 조각을 찾습니다.

    Thread.Sleep(3000);
    Console.WriteLine();
    
  2. Thread.Sleep 또는 C++의 경우,std::this_thread::sleep_for 문의 왼쪽 여백을 마우스 왼쪽 단추로 클릭하고 새로운 중단점을 삽입합니다.

    여백의 빨간색 원은 이 위치에 중단점이 설정되었음을 나타냅니다.

  3. 디버그 메뉴에서 디버깅 시작(F5)을 선택합니다.

    Visual Studio가 솔루션을 빌드하고, 디버거가 연결된 상태로 앱이 실행되기 시작하고, 앱이 중단점에서 중지됩니다.

  4. 소스 코드 편집기에서 중단점이 포함된 줄을 찾습니다.

스레드 마커 찾기

  1. 디버그 도구 모음에서 소스의 스레드 표시 단추(Show Threads in Source)를 선택합니다.

  2. F11 키를 두 번 눌러 디버거를 진행합니다.

  3. 창 왼쪽의 여백을 확인합니다. 이 줄에는 스레드 두 개가 꼬여 있는 모습의 스레드 마커 아이콘(Thread Marker)이 표시됩니다. 스레드 마커는 이 위치에서 스레드가 중지되었음을 나타냅니다.

    중단점이 스레드 마커의 일부를 가릴 수 있습니다.

  4. 스레드 마커에 포인터를 올려 놓습니다. 중지된 각 스레드의 이름과 스레드 ID 번호를 알려주는 DataTip이 나타납니다. 여기서는 이름이 아마도 <noname>일 것입니다.

    Screenshot of the Thread ID in a DataTip.

  5. 스레드 마커를 선택하면 바로 가기 메뉴에서 사용 가능한 옵션이 표시됩니다.

스레드 위치 보기

병렬 스택 창에서 스레드 보기와 (작업 기반 프로그래밍의 경우) 작업 보기 간에 전환할 수 있으며, 각 스레드의 호출 스택 정보를 볼 수 있습니다. 이 앱에서는 스레드 보기를 사용할 수 있습니다.

  1. 디버그>Windows>병렬 스택을 선택하여 병렬 스택 창을 엽니다. 다음과 비슷한 내용이 표시됩니다. 정확한 정보는 각 스레드의 현재 위치, 하드웨어 및 프로그래밍 언어에 따라 달라질 수 있습니다.

    Screenshot of the Parallel Stacks Window.

    이 예제에서는 관리 코드에 대한 다음 정보가 왼쪽에서 오른쪽으로 표시됩니다.

    • 현재 스레드(노란색 화살표)가 ServerClass.InstanceMethod를 입력했습니다. ServerClass.InstanceMethod 위로 마우스를 가져가면 스레드의 스레드 ID 및 스택 프레임을 볼 수 있습니다.
    • 스레드 31724가 스레드 20272가 소유한 잠금을 기다리고 있습니다.
    • [외부 코드]에서 주 스레드(왼쪽)가 중지되었습니다. 외부 코드 표시를 선택하면 자세히 볼 수 있습니다.

    Parallel Stacks Window

    이 예제에서는 관리 코드에 대한 다음 정보가 왼쪽에서 오른쪽으로 표시됩니다.

    • 주 스레드(왼쪽)가 Thread.Start에서 중지되었으며, 여기서 중지 지점은 스레드 마커 아이콘(Thread Marker)으로 식별합니다.
    • 두 스레드가 ServerClass.InstanceMethod를 입력했으며, 그 중 하나는 현재 스레드(노란색 화살표)이고 다른 스레드는 Thread.Sleep에서 중지되었습니다.
    • 새 스레드(오른쪽)도 시작되지만, ThreadHelper.ThreadStart에서 중지되었습니다.
  2. 목록 보기에서 스레드를 보려면 디버그>Windows>스레드를 선택합니다.

    Screenshot of the Threads Window.

    이 보기에서는 스레드 20272가 주 스레드이며 현재 외부 코드, 특히 System.Console.dll에 있는 것을 쉽게 확인할 수 있습니다.

    참고 항목

    스레드 창 사용에 대한 자세한 내용은 연습: 다중 스레드 애플리케이션 디버그를 참조하세요.

  3. 병렬 스택 또는 스레드 창의 항목을 마우스 오른쪽 단추로 클릭하면 바로 가기 메뉴에서 사용 가능한 옵션이 표시됩니다.

    이러한 오른쪽 클릭 메뉴에서 다양한 작업을 수행할 수 있습니다. 이 자습서에서는 병렬 조사식 창(다음 섹션)에서 이러한 세부 정보를 자세히 살펴봅니다.

변수에 조사식 설정

  1. 디버그>Windows>병렬 조사식>병렬 조사식 1을 선택하여 병렬 조사식 창을 엽니다.

  2. <Add Watch> 텍스트(또는 4번째 열의 빈 헤더 셀)가 표시되는 셀을 선택하고 data를 입력합니다.

    각 스레드의 데이터 변수 값이 창에 표시됩니다.

  3. <Add Watch> 텍스트(또는 5번째 열의 빈 헤더 셀)가 표시되는 셀을 선택하고 count를 입력합니다.

    각 스레드의 count 변수 값이 창에 표시됩니다. 이 정보가 아직 표시되지 않으면 F11 키를 몇 번 눌러 디버거에서 스레드 실행을 진행해 보세요.

    Parallel Watch Window

  4. 창에 있는 행 중 하나를 마우스 오른쪽 단추로 클릭하면 사용 가능한 옵션이 표시됩니다.

스레드에 플래그 지정 및 스레드의 플래그 해제

스레드에 플래그를 지정하여 중요한 스레드를 추적하고 나머지 스레드를 무시할 수 있습니다.

  1. 병렬 조사식 창에서 Shift 키를 누른 상태로 여러 행을 선택합니다.

  2. 마우스 오른쪽 단추로 클릭하고 플래그를 선택합니다.

    선택한 모든 스레드에 플래그가 지정됩니다. 이제 플래그가 지정된 스레드만 표시하도록 필터링할 수 있습니다.

  3. 병렬 조사식 창에서 플래그가 지정된 스레드만 표시 단추(Show Flagged Threads)를 선택합니다.

    플래그가 지정된 스레드만 목록에 나타납니다.

    일부 스레드에 플래그를 지정한 후에는 코드 편집기에서 코드 줄을 마우스 오른쪽 단추로 클릭하고 플래그 지정된 스레드를 커서까지 실행을 선택할 수 있습니다. 플래그가 지정된 모든 스레드가 도달할 코드를 선택해야 합니다. Visual Studio는 선택한 코드 줄에서 스레드를 일시 중지하므로, 스레드를 중지 및 재개하여 실행 순서를 쉽게 제어할 수 있습니다.

  4. 플래그가 지정된 스레드만 표시 단추를 다시 선택하여 모든 스레드 표시 모드로 돌아갑니다.

  5. 스레드의 플래그를 해제하려면 병렬 조사식 창에서 플래그가 지정된 하나 이상의 스레드를 마우스 오른쪽 단추로 클릭하고 플래그 해제를 선택합니다.

스레드 실행 중지 및 재개

스레드를 중지 및 재개(일시 중단 및 다시 시작)하여 스레드가 작업을 수행하는 순서를 제어할 수 있습니다. 이를 통해 교착 상태 및 경합 상태와 같은 동시성 문제를 해결할 수 있습니다.

  1. 병렬 조사식 창에서 모든 행을 선택한 상태로 마우스 오른쪽 단추를 클릭하고 중지를 선택합니다.

    두 번째 열에는 각 행의 일시 중지 아이콘이 표시됩니다. 일시 중지 아이콘은 스레드가 중지되었음을 나타냅니다.

  2. 행을 하나만 선택하여 나머지 행을 선택 취소합니다.

  3. 행을 마우스 오른쪽 단추로 클릭하고 재개를 선택합니다.

    일시 중지 아이콘이 이 행에서 사라지며, 스레드가 더 이상 중지 상태가 아니라는 의미입니다.

  4. 코드 편집기로 전환하여 F11 키를 누릅니다. 중지되지 않은 스레드만 실행됩니다.

    앱에서 새 스레드 몇 개를 인스턴스화할 수도 있습니다. 새 스레드는 플래그가 해제되며 중지되지 않습니다.

조건부 중단점을 사용하여 단일 스레드 팔로우

디버거에서 단일 스레드 실행을 팔로우하면 도움이 될 수 있습니다. 팔로우하는 방법 중 하나는 관심 없는 스레드를 중지하는 것입니다. 특정 버그를 재현해야 하는 경우처럼 다른 스레드를 중지하지 않고 단일 스레드를 팔로우해야 하는 경우가 있습니다. 다른 스레드를 중지하지 않고 스레드를 팔로우하려면 관심이 있는 스레드 외에는 코드를 중단하지 않아야 합니다. 이 작업을 수행하려면 조건부 중단점을 설정하면 됩니다.

스레드 이름 또는 스레드 ID와 같은 여러 조건에 중단점을 설정할 수 있습니다. 각 스레드에 고유하다는 것을 알고 있는 데이터에 조건을 설정하면 도움이 될 수 있습니다. 이 접근 방식은 특정 스레드보다 특정 데이터 값에 관심이 더 많을 때 디버깅 중 일반적입니다.

  1. 앞에서 만든 중단점을 마우스 오른쪽 단추로 클릭하고 조건을 선택합니다.

  2. 중단점 설정 창에서 조건식으로 data == 5를 입력합니다.

    Conditional Breakpoint

    특정 스레드에 더 관심이 있으면 조건에 스레드 이름 또는 스레드 ID를 사용합니다. 중단점 설정 창에서 이 작업을 수행하려면 조건식 대신 필터를 선택하고 필터 팁을 따릅니다. 디버거를 다시 시작할 때 스레드 ID가 변경되므로, 앱 코드에서 스레드 이름을 지정할 수 있습니다.

  3. 중단점 설정 창을 닫습니다.

  4. 다시 시작 Restart App 단추를 선택하여 디버깅 세션을 다시 시작합니다.

    데이터 변수 값이 5인 스레드에서 코드가 중단됩니다. 병렬 조사식 창에서 현재 디버거 컨텍스트를 나타내는 노란색 화살표를 찾습니다.

  5. 이제 코드를 프로시저 단위로 실행(F10)하고 한 단계씩 코드를 실행(F11)한 다음, 단일 스레드 실행을 팔로우할 수 있습니다.

    중단점 조건이 스레드에 대해 고유하고 디버거가 다른 스레드의 다른 중단점에 도달하지 않는 한(다른 중단점을 사용하지 않도록 설정해야 할 수도 있음), 다른 스레드로 전환하지 않고 코드를 프로시저 단위로 실행하고 코드를 한 단계씩 실행할 수 있습니다.

    참고 항목

    디버거를 진행하면 모든 스레드가 실행됩니다. 그러나 다른 스레드 중 하나가 중단점에 도달하지 않으면 디버거가 다른 스레드의 코드를 중단하지 않습니다.