diff --git a/docs/debugger/get-started-debugging-multithreaded-apps.md b/docs/debugger/get-started-debugging-multithreaded-apps.md index 08f1d92ab33..2ce949e2941 100644 --- a/docs/debugger/get-started-debugging-multithreaded-apps.md +++ b/docs/debugger/get-started-debugging-multithreaded-apps.md @@ -20,11 +20,13 @@ ms.subservice: debug-diagnostics Visual Studio provides several tools and user interface elements to help you debug multithreaded applications. This tutorial shows how to use thread markers, the **Parallel Stacks** window, the **Parallel Watch** window, conditional breakpoints, and filter breakpoints. Completing this tutorial familiarizes you with Visual Studio features for debugging multithreaded applications. +::: moniker range=">=vs-2022" For tutorials that are more scenario-focused, see the following articles. - [Debug a deadlock using Threads view](../debugger/how-to-use-the-threads-window.md). - [Debug an async application (.NET)](../debugger/walkthrough-debugging-a-parallel-application.md). +::: moniker-end The first step is to create a multithreaded application project. @@ -268,6 +270,9 @@ In the **Parallel Stacks** window, you can switch between a Threads view and (fo - A new thread (on the right) is also starting but is stopped on `ThreadHelper.ThreadStart`. ::: moniker-end + > [!NOTE] + > For more information on using the **Threads** view, see [Debug a deadlock using the Threads view](../debugger/how-to-use-the-threads-window.md). + 2. To view the threads in a list view, select **Debug** > **Windows** > **Threads**. ::: moniker range=">= vs-2022" @@ -276,9 +281,6 @@ In the **Parallel Stacks** window, you can switch between a Threads view and (fo In this view, you can easily see that thread 20272 is the Main thread and is currently located in external code, specifically *System.Console.dll*. ::: moniker-end - > [!NOTE] - > For more information on using the **Threads** window, see [Walkthrough: Debug a Multithreaded Application](../debugger/how-to-use-the-threads-window.md). - 3. Right-click entries in the **Parallel Stacks** or **Threads** window to see the available options on the shortcut menu. You can take various actions from these right-click menus. For this tutorial, you explore more of these details in the **Parallel Watch** window (next sections). diff --git a/docs/debugger/how-to-use-the-threads-window.md b/docs/debugger/how-to-use-the-threads-window.md index 673f357fe4c..f2a3f9098f1 100644 --- a/docs/debugger/how-to-use-the-threads-window.md +++ b/docs/debugger/how-to-use-the-threads-window.md @@ -1,7 +1,7 @@ --- title: Debug a deadlock using the Threads view description: Debug a deadlock in a multithreaded application by using the Threads view of the Parallel Stacks window in the Visual Studio integrated development environment (IDE). -ms.date: 7/25/2025 +ms.date: 8/19/2025 ms.topic: how-to dev_langs: - CSharp @@ -21,9 +21,9 @@ monikerRange: '>= vs-2022' --- # Debug a deadlock using the Threads view -This tutorial shows how to use the **Threads** view of **Parallel Stacks** windows to debug a C# multithreaded application. This window helps you understand and verify the run-time behavior of multithreaded code. +This tutorial shows how to use the **Threads** view of **Parallel Stacks** windows to debug a multithreaded application. This window helps you understand and verify the run-time behavior of multithreaded code. -The Threads view is also supported for C++ and Visual Basic, so the same principles described in this article for C# also apply to C++ and Visual Basic. +The Threads view is supported for C#, C++, and Visual Basic. Sample code is provided for C# and C++, but some of the content and illustrations apply only to the C# sample code.principles. The Threads view helps you to: @@ -31,7 +31,15 @@ The Threads view helps you to: - Help identify issues such as blocked or deadlocked threads. -## C# sample +## Multithreaded call stacks + +Identical sections of the call stack are grouped together to simplify the visualization for complex apps. + +The following conceptual animation shows how grouping is applied to call stacks. Only identical segments of a call stack are grouped. + +![Illustration of the grouping of call stacks.](../debugger/media/vs-2022/debug-multithreaded-call-stacks.gif) + +## Sample code overview (C#, C++) The sample code in this walkthrough is for an application that simulates a day in the life of a gorilla. The purpose of the exercise is to understand how to use the Threads view of the Parallel Stacks window to debug a multithreaded application. @@ -46,14 +54,6 @@ To make the call stack intuitive, the sample app performs the following sequenti 1. Gorilla eats. 1. Gorilla engages in monkey business. -## Multithreaded call stacks - -Identical sections of the call stack are grouped together to simplify the visualization for complex apps. - -The following conceptual animation shows how grouping is applied to call stacks. Only identical segments of a call stack are grouped. - -![Illustration of the grouping of call stacks.](../debugger/media/vs-2022/debug-multithreaded-call-stacks.gif) - ## Create the sample project To create the project: @@ -64,23 +64,24 @@ To create the project: On the Start window, choose **New project**. - On the **Create a new project** window, enter or type *console* in the search box. Next, choose **C#** from the Language list, and then choose **Windows** from the Platform list. + On the **Create a new project** window, enter or type *console* in the search box. Next, choose **C#** or **C++** from the Language list, and then choose **Windows** from the Platform list. - After you apply the language and platform filters, choose the **Console App** for .NET, and then choose **Next**. + After you apply the language and platform filters, choose the **Console App** for your chosen language, and then choose **Next**. > [!NOTE] > If you don't see the correct template, go to **Tools** > **Get Tools and Features...**, which opens the Visual Studio Installer. Choose the **.NET desktop development** workload, then choose **Modify**. In the **Configure your new project** window, type a name or use the default name in the **Project name** box. Then, choose **Next**. - For .NET, choose either the recommended target framework or .NET 8, and then choose **Create**. + For a .NET project, choose either the recommended target framework or .NET 8, and then choose **Create**. A new console project appears. After the project has been created, a source file appears. -1. Open the *.cs* code file in the project. Delete its contents to create an empty code file. +1. Open the *.cs* (or *.cpp*) code file in the project. Delete its contents to create an empty code file. 1. Paste the following code for your chosen language into the empty code file. + ### [C#](#tab/csharp) ```csharp using System.Diagnostics; @@ -191,6 +192,84 @@ To create the project: } } ``` + + ### [C++](#tab/cpp) + ```cpp + #include + #include + #include + #include + #include + + namespace Jungle { + + std::mutex tree; + std::mutex banana_bunch; + + void FindBananas() { + // Lock tree first, then banana + std::lock_guard lock1(tree); + std::lock_guard lock2(banana_bunch); + std::cout << "Got bananas." << std::endl; + } + + class Gorilla { + bool lockTreeFirst; + public: + Gorilla(bool lockTreeFirst_) : lockTreeFirst(lockTreeFirst_) {} + + void WakeUp() { + MorningWalk(); + } + + void MorningWalk() { + __debugbreak(); + if (lockTreeFirst) { + std::unique_lock lock1(tree); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Simulate barrier + FindBananas(); + GobbleUpBananas(); + } + else { + std::unique_lock lock2(banana_bunch); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Simulate barrier + FindBananas(); + GobbleUpBananas(); + } + } + + void GobbleUpBananas() { + std::cout << "Trying to gobble up food..." << std::endl; + DoSomeMonkeyBusiness(); + } + + void DoSomeMonkeyBusiness() { + std::this_thread::sleep_for(std::chrono::seconds(1)); + std::cout << "Monkey business done" << std::endl; + } + }; + + void Gorilla_Start(bool lockTreeFirst) { + __debugbreak(); + Gorilla koko(lockTreeFirst); + koko.WakeUp(); + } + + } // namespace Multithreaded_Deadlock + + int main() { + using namespace Jungle; + std::vector threads; + threads.emplace_back(Gorilla_Start, true); // First gorilla locks tree then banana + threads.emplace_back(Gorilla_Start, false); // Second gorilla locks banana then tree + + for (auto& t : threads) { + t.join(); + } + return 0; + } + ``` + After you update the code file, save your changes and build the solution. @@ -204,6 +283,9 @@ To start debugging: 1. On the **Debug** menu, select **Start Debugging** (or **F5**) and wait for the first `Debugger.Break()` to be hit. + > [!NOTE] + > In C++, the debugger pauses in `__debug_break()`. The rest of the code references and illustrations in this article are for the C# version, but the same debugging principles apply to C++. + 1. Press **F5** once, and the debugger pauses again on the same `Debugger.Break()` line. This pauses in the second call to `Gorilla_Start`, which occurs within a second thread. @@ -251,6 +333,9 @@ To start debugging: The delay is caused by a deadlock. Nothing appears in the Threads view because even though threads may be blocked you aren't currently paused in the debugger. + > [!NOTE] + > In C++, you also see a debug error indicating that `abort()` has been called. + > [!TIP] > The **Break All** button is a good way to get call stack information if a deadlock occurs or all threads are currently blocked. @@ -260,6 +345,9 @@ To start debugging: The top of the call stack in the Threads view shows that `FindBananas` is deadlocked. The execution pointer in `FindBananas` is a curled green arrow, indicating the current debugger context but also it tells us that the threads are not currently running. + > [!NOTE] + > In C++, you don't see the helpful "deadlock detected" information and icons. However, you still find the curled green arrow in `Jungle.FindBananas`, hinting at the location of the deadlock. + In the code editor, we find the curled green arrow in the `lock` function. The two threads are blocked on the `lock` function in the `FindBananas` method. :::image type="content" source="../debugger/media/vs-2022/debug-multithreaded-parallel-stacks-break-all-editor.png" border="false" alt-text="Screenshot of code editor after selecting Break All." lightbox="../debugger/media/vs-2022/debug-multithreaded-parallel-stacks-break-all-editor.png"::: diff --git a/docs/debugger/using-the-parallel-stacks-window.md b/docs/debugger/using-the-parallel-stacks-window.md index bf08dac499e..a09a30de07a 100644 --- a/docs/debugger/using-the-parallel-stacks-window.md +++ b/docs/debugger/using-the-parallel-stacks-window.md @@ -91,10 +91,10 @@ Icon|Description| |![Yellow arrow](media/icon-parallel-yellow-arrow.png)|Indicates the current location (active stack frame) of the current thread.| |![Threads icon](media/icon-parallelthreads.gif)|Indicates the current location (active stack frame) of a non-current thread.| |![Green arrow](media/icon-parallel-green-arrow.png)|Indicates the current stack frame (the current debugger context). The method name is bold wherever it appears.| -|![Status Error](media/vs-2022/icon-status-error.png)|Indicates that the current stack frame has Critical status warning such as Deadlock.| -|![Status Excluded](media/vs-2022/icon-status-excluded.png)|Indicates the deadlocked node.| -|![Status Information](media/vs-2022/icon-status-information.png)|Indicates that the current stack frame has additional information such as Waiting on, Waiting on lock, owned by, etc. | -|![Status Blocked](media/vs-2022/icon-status-block.png)|Indicates that the current task is in blocked/waiting state, etc. | +|![Status Error](media/vs-2022/icon-status-error.png)|(.NET) Indicates that the current stack frame has Critical status warning such as Deadlock.| +|![Status Excluded](media/vs-2022/icon-status-excluded.png)|(.NET) Indicates the deadlocked node.| +|![Status Information](media/vs-2022/icon-status-information.png)|(.NET) Indicates that the current stack frame has additional information such as Waiting on, Waiting on lock, owned by, etc. | +|![Status Blocked](media/vs-2022/icon-status-block.png)|(.NET) Indicates that the current task is in blocked/waiting state, etc. | |![Status Running](media/vs-2022/icon-status-running.png)|Indicates the currently running task.| ::: moniker-end @@ -194,15 +194,13 @@ The following table describes the main features of the **Threads** view: ::: moniker-end ## Tasks view -If your app uses objects (managed code) or `task_handle` objects (native code) to express parallelism, you can use **Tasks** view. **Tasks** view shows call stacks of tasks instead of threads. -In **Tasks** view: +For .NET apps using the async/await pattern, the Tasks view is the most helpful for debugging. For a step-by-step tutorial, see [Debug an async application](../debugger/walkthrough-debugging-a-parallel-application.md). -- Call stacks of threads that aren't running tasks aren't shown. -- Call stacks of threads that are running tasks are visually trimmed at the top and bottom, to show the most relevant frames for tasks. -- When several tasks are on one thread, the call stacks of those tasks are shown in separate nodes. +In **Tasks** view, you can: -To see an entire call stack, switch back to **Threads** view by right-clicking in a stack frame and selecting **Go to Thread**. +- View call stack visualizations for apps that use the async/await pattern. +- Identify async code that is scheduled to run but isn't yet running. The following illustration shows the **Threads** view at the top and the corresponding **Tasks** view at the bottom. @@ -252,8 +250,6 @@ These video tutorials demonstrate how you can use the Threads and Tasks views of ## Related content - [Get started debugging a multithreaded application](../debugger/get-started-debugging-multithreaded-apps.md) -- [Debug an async application (.NET)](../debugger/walkthrough-debugging-a-parallel-application.md) -- [Debug a deadlock](../debugger/how-to-use-the-threads-window.md) - [Switch to Another Thread While Debugging in Visual Studio](../debugger/how-to-switch-to-another-thread-while-debugging.md) - [Debugging managed code](/visualstudio/debugger/) - [Parallel programming](/dotnet/standard/parallel-programming/index) diff --git a/docs/debugger/using-the-tasks-window.md b/docs/debugger/using-the-tasks-window.md index 174b64b2991..1e650261d2a 100644 --- a/docs/debugger/using-the-tasks-window.md +++ b/docs/debugger/using-the-tasks-window.md @@ -9,7 +9,6 @@ dev_langs: - "CSharp" - "VB" - "FSharp" - - "C++" helpviewer_keywords: - "debugger, parallel tasks window" author: "mikejo5000" @@ -17,7 +16,7 @@ ms.author: "mikejo" manager: mijacobs ms.subservice: debug-diagnostics --- -# Using the Tasks Window (C#, Visual Basic, C++) +# Using the Tasks Window (C#, Visual Basic) The **Tasks** window resembles the **Threads** window, except that it shows information about asynchronous tasks created using the async/await pattern, also called the [Task-based asynchronous pattern (TAP)](/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap) instead of thread-based information. Like threads, tasks represent asynchronous operations that can run concurrently; however, multiple tasks may run on the same thread. @@ -30,7 +29,7 @@ In .NET code, you can use the **Tasks** window when you work with apps using the ::: moniker-end > [!TIP] -> For C/C++ code, the **Threads** view in the **Parallel Stacks** window is typically the most helpful when you need to debug [task groups](/cpp/parallel/concrt/task-parallelism-concurrency-runtime), [parallel algorithms](/cpp/parallel/concrt/parallel-algorithms), [asynchronous agents](/cpp/parallel/concrt/asynchronous-agents), and [lightweight tasks](/cpp/parallel/concrt/task-scheduler-concurrency-runtime). For more information, see [View threads and tasks in the Parallel Stacks window](../debugger/using-the-parallel-stacks-window.md). +> For C/C++ code, use the **Threads** view in the **Parallel Stacks** window when you need to debug [task groups](/cpp/parallel/concrt/task-parallelism-concurrency-runtime), [parallel algorithms](/cpp/parallel/concrt/parallel-algorithms), [asynchronous agents](/cpp/parallel/concrt/asynchronous-agents), and [lightweight tasks](/cpp/parallel/concrt/task-scheduler-concurrency-runtime). For more information, see [View threads and tasks in the Parallel Stacks window](../debugger/using-the-parallel-stacks-window.md). You can use the **Tasks** window whenever you break into the debugger. You can access it on the **Debug** menu by clicking **Windows** and then clicking **Tasks**. The following illustration shows the **Tasks** window in its default mode. @@ -117,8 +116,6 @@ The **Switch to Task** command makes the current task the active task. The **Swi ## Related content -- [Debug an async application (.NET)](../debugger/walkthrough-debugging-a-parallel-application.md) -- [Debug a deadlock](../debugger/how-to-use-the-threads-window.md) - [First look at the debugger](../debugger/debugger-feature-tour.md) - [Debugging Managed Code](/visualstudio/debugger/) - [Parallel Programming](/dotnet/standard/parallel-programming/index) diff --git a/docs/debugger/walkthrough-debugging-a-parallel-application.md b/docs/debugger/walkthrough-debugging-a-parallel-application.md index 9fe6f7c2725..db3f01810ee 100644 --- a/docs/debugger/walkthrough-debugging-a-parallel-application.md +++ b/docs/debugger/walkthrough-debugging-a-parallel-application.md @@ -1,7 +1,7 @@ --- title: "Debug an async application" description: Debug an async application by using the Parallel Stacks windows in the Visual Studio integrated development environment (IDE). -ms.date: "07/14/2025" +ms.date: "08/19/2025" ms.topic: "conceptual" dev_langs: - "CSharp" @@ -21,7 +21,7 @@ monikerRange: '>= vs-2022' This tutorial shows how to use the Tasks view of **Parallel Stacks** window to debug a C# async application. This window helps you understand and verify the run-time behavior of code that uses the async/await pattern, also called the [Task-based asynchronous pattern (TAP)](/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap). -For apps using the [Task Parallel Library (TPL)](/dotnet/standard/parallel-programming/task-parallel-library-tpl) but not the async/await pattern, or for C++ apps using the [Concurrency Runtime](/cpp/parallel/concrt/concurrency-runtime), the **Threads** view in the **Parallel Stacks** window is the most useful tool for debugging. For more information, see [View threads and tasks in the Parallel Stacks window](../debugger/using-the-parallel-stacks-window.md). +For apps using the [Task Parallel Library (TPL)](/dotnet/standard/parallel-programming/task-parallel-library-tpl) but not the async/await pattern, or for C++ apps using the [Concurrency Runtime](/cpp/parallel/concrt/concurrency-runtime), use the **Threads** view in the **Parallel Stacks** window for debugging. For more information, see [Debug a deadlock](../debugger/how-to-use-the-threads-window.md) and [View threads and tasks in the Parallel Stacks window](../debugger/using-the-parallel-stacks-window.md). The Tasks view helps you to: @@ -31,21 +31,6 @@ The Tasks view helps you to: - Help identify issues such as the sync-over-async pattern along with hints related to potential issues such as blocked or waiting tasks. The [sync-over-async code pattern](https://devblogs.microsoft.com/pfxteam/should-i-expose-synchronous-wrappers-for-asynchronous-methods/) refers to code that is calling asynchronous methods in a synchronous fashion, which is known to block threads and is the most common cause of thread pool starvation. -## C# sample - -The sample code in this walkthrough is for an application that simulates a day in the life of a gorilla. The purpose of the exercise is to understand how to use the Tasks view of the Parallel Stacks window to debug an async application. - -The sample includes an example of using the sync-over-async antipattern, which can result in thread pool starvation. - -To make the call stack intuitive, the sample app performs the following sequential steps: - -1. Creates an object representing a gorilla. -1. Gorilla wakes up. -1. Gorilla goes on a morning walk. -1. Gorilla finds bananas in the jungle. -1. Gorilla eats. -1. Gorilla engages in monkey business. - ## Async call stacks The Tasks view in Parallel Stacks provides a visualization for async call stacks, so you can see what's happening (or supposed to happen) in your application. @@ -66,6 +51,21 @@ Here are a few important points to remember when interpreting data in the Tasks ![Illustration of the grouping of virtual call stacks.](../debugger/media/vs-2022/debug-asynchronous-virtual-call-stacks-top-bottom.gif) +## C# sample + +The sample code in this walkthrough is for an application that simulates a day in the life of a gorilla. The purpose of the exercise is to understand how to use the Tasks view of the Parallel Stacks window to debug an async application. + +The sample includes an example of using the sync-over-async antipattern, which can result in thread pool starvation. + +To make the call stack intuitive, the sample app performs the following sequential steps: + +1. Creates an object representing a gorilla. +1. Gorilla wakes up. +1. Gorilla goes on a morning walk. +1. Gorilla finds bananas in the jungle. +1. Gorilla eats. +1. Gorilla engages in monkey business. + ## Create the sample project 1. Open Visual Studio and create a new project. diff --git a/docs/profiling/troubleshoot-profiler-errors.md b/docs/profiling/troubleshoot-profiler-errors.md index 19a8788783c..c664981990b 100644 --- a/docs/profiling/troubleshoot-profiler-errors.md +++ b/docs/profiling/troubleshoot-profiler-errors.md @@ -1,7 +1,7 @@ --- title: Troubleshoot profiling errors description: Troubleshoot profiling errors, including no data in filters, slow results, and source information unavailable, and follow error message guidance to fix issues. -ms.date: 06/28/2023 +ms.date: 08/19/2025 ms.topic: how-to author: mikejo5000 ms.author: mikejo @@ -74,7 +74,7 @@ After a long memory profiling session, any attempt to analyze the result is met There was a mismatch between the snapshot information captured by the memory tool and that of the collection agent. This result means that the memory tool wasn't able to find the heap state file for a native snapshot. Or, this result the memory tool couldn't match the GC start time of the snapshot to the one registered in the *diagsession* file to retrieve the GCStats. **How to fix** -This issue was due to a bug in the tool that was fixed in 17.3. Upgrading to a later version should solve the issue. If the issue is still persistent after upgrading, create a feedback ticket and attach to the ticket: +This issue was due to a bug in the tool that was fixed in Visual Studio 2022 version 17.3. Upgrading to a later version should solve the issue. If the issue is still persistent after upgrading, create a feedback ticket and attach to the ticket: - The *diagsession* file - A minidump of Visual Studio