- View threads in the Visual Studio debugger by using the Threads window (C#, Visual Basic, C++)
- Use the Threads window
- To display the Threads window in break mode or run mode
- To display or hide a column
- Display flagged threads
- To display only flagged threads
- Freeze and thaw threads
- To freeze or thaw execution of a thread
- Switch to another thread
- To switch to another thread
- Group and sort threads
- To sort threads
- To group threads
- To sort threads within groups
- To expand or collapse all groups
- Search for specific threads
- To search for specific threads
- Display thread call stacks and switch between frames
- To view the call stack of a thread
- Controlling Processes and Threads
- Displaying Processes and Threads
- Setting the Current Process and Thread
- Freezing and Suspending Threads
- Threads and Processes in Other Commands
- Multiple Systems
- Creating Threads
View threads in the Visual Studio debugger by using the Threads window (C#, Visual Basic, C++)
In the Threads window, you can examine and work with threads in the application that you’re debugging. For step-by-step guidance on how to use the Threads window, see Walkthrough: Debug by using the Threads window.
Use the Threads window
The Threads window contains a table where each row describes a separate thread in your application. By default, the table lists all the threads in your application, but you can filter the list to show only the threads that interest you. Each column describes a different type of information. You can also hide some columns. If you display all the columns, the following columns appear, from left to right:
Flag: In this unlabeled column, you can mark a thread to which you want to pay special attention. For information about how to flag a thread, see How to: Flag and unflag threads.
Current thread: In this unlabeled column, a yellow arrow indicates the current thread. An arrow outline indicates the current debugger context for a non-current thread.
ID: Displays the identification number for each thread.
Managed ID: Displays the managed identification numbers for managed threads.
Category: Displays the category of threads as either user interface threads, remote procedure call handlers, or worker threads. A special category identifies the main thread of the application.
Name: Identifies each thread by name, if it has one, or as .
Location: Shows where the thread is running. You can expand this location to show the full call stack for the thread.
Priority: An advanced column (hidden by default) that displays the priority or precedence that the system has assigned to each thread.
Affinity Mask: An advanced column (hidden by default) that shows the processor affinity mask for each thread. In a multiprocessor system, the affinity mask determines which processors on which a thread can run.
Suspended Count: An advanced column (hidden by default) that displays the suspended count. This count determines whether a thread can run. For more information about suspended counts, see Freeze and thaw threads.
Process Name: An advanced column (hidden by default) that displays the process to which each thread belongs. The data in this column can be useful when you’re debugging many processes.
Process ID: An advanced column (hidden by default) that displays the process ID to which each thread belongs.
Transport Qualifier: An advanced column (hidden by default) that uniquely identifies the machine to which the debugger is connected.
To display the Threads window in break mode or run mode
- While Visual Studio is in debug mode, select the Debug menu, point to Windows, and then select Threads.
To display or hide a column
- In the toolbar at the top of the Threads window, select Columns. Then, select or clear the name of the column that you want to display or hide.
Display flagged threads
You can flag a thread that you want to give special attention by marking it with an icon in the Threads window. For more information, see How to: Flag and Unflag threads. In the Threads window, you can choose to display all the threads or only the flagged threads.
To display only flagged threads
- Choose Show Flagged Threads Only in the toolbar at the top of the Threads window. (If it’s dimmed, you’ll need to flag some threads first.)
Freeze and thaw threads
When you freeze a thread, the system won’t start execution of the thread even if resources are available.
In native code, you can suspend or resume threads by calling the Windows functions SuspendThread and ResumeThread . Or, call the MFC functions CWinThread::SuspendThread and CWinThread::ResumeThread. If you call SuspendThread or ResumeThread , the suspended count shown in the Threads window will be changed. The suspended count doesn’t change if you freeze or thaw a native thread. A thread can’t execute in native code unless it’s thawed and has a suspended count of zero.
In managed code, the suspended count changes when you freeze or thaw a thread. If you freeze a thread in managed code, its suspended count is 1. When you freeze a thread in native code, its suspended count is 0, unless you used the SuspendThread call.
When you debug a call from native code to managed code, the managed code runs in the same physical thread as the native code that called it. Suspending or freezing the native thread freezes the managed code also.
To freeze or thaw execution of a thread
In the toolbar at the top of the Threads window, select Freeze Threads or Thaw Threads.
This action affects only threads that are selected in the Threads window.
Switch to another thread
A yellow arrow indicates the current thread (and the location of the execution pointer). A green arrow with a curly tail indicates a non-current thread has the current debugger context.
To switch to another thread
Follow either of the following steps:
Double-click any thread.
Right-click a thread and select Switch To Thread.
Group and sort threads
When you group threads, a heading appears in the table for each group. The heading contains a group description, such as Worker Thread or Unflagged Threads, and a tree control. The member threads of each group appear under the group heading. If you want to hide the member threads for a group, use the tree control to collapse the group.
Because grouping takes precedence over sorting, you can group threads by category, for example, and then sort them by ID within each category.
To sort threads
In the toolbar at the top of the Threads window, select the button at the top of any column.
The threads are now sorted by the values in that column.
If you want to reverse the sort order, select the same button again.
Threads that appeared at the top of the list now appear on the bottom.
To group threads
- In the Threads window toolbar, select the Group by list, then select the criteria that you want to group threads by.
To sort threads within groups
In the toolbar at the top of the Threads window, select the Group by list, then select the criteria that you want to group threads by.
In the Threads window, select the button at the top of any column.
The threads are now sorted by the values in that column.
To expand or collapse all groups
- In the toolbar at the top of the Threads window, select Expand groups or Collapse groups.
Search for specific threads
You can search for threads that match a specified string in the Threads window. When you search for threads, the window displays all the threads matching the search string in any column. This information includes the thread location that appears at the top of the call stack in the Location column. By default, the full call stack isn’t searched.
To search for specific threads
In the toolbar at the top of the Threads window, go to the Search box and either:
- Enter a search string and then press Enter.
- Select the drop-down list next to the Search box and select a search string from a previous search.
(Optional) To include the full call stack in your search, select Search Call Stack.
Display thread call stacks and switch between frames
In a multithreaded program, each thread has its own call stack. The Threads window provides a convenient way to view these stacks.
For a visual representation of the call stack for each thread, use the Parallel Stacks window.
To view the call stack of a thread
In the Location column, select the inverted triangle next to the thread location.
The location expands to show the call stack for the thread.
Controlling Processes and Threads
When you are performing user-mode debugging, you activate, display, freeze, unfreeze, suspend, and unsuspend processes and threads.
The current or active process is the process that is currently being debugged. Similarly, the current or active thread is the thread that the debugger is currently controlling. The actions of many debugger commands are determined by the identity of the current process and thread. The current process also determines the virtual address mappings that the debugger uses.
When debugging begins, the current process is the one that the debugger is attached to or that caused the exception that broke into the debugger. Similarly, the current thread is the one that was active when the debugger attached to the process or that caused the exception. However, you can use the debugger to change the current process and thread and to freeze or unfreeze individual threads.
In kernel-mode debugging, processes and threads are not controlled by the methods that are described in this section. For more information about how processes and threads are manipulated in kernel mode, see Changing Contexts.
Displaying Processes and Threads
To display process and thread information, you can use the following methods:
Setting the Current Process and Thread
To change the current process or thread, you can use the following methods:
Freezing and Suspending Threads
The debugger can change the execution of a thread by suspending the thread or by freezing the thread. These two actions have somewhat different effects.
Each thread has a suspend count that is associated with it. If this count is one or larger, the system does not run the thread. If the count is zero or lower, the system runs the thread when appropriate.
Typically, each thread has a suspend count of zero. When the debugger attaches to a process, it increments the suspend counts of all threads in that process by one. If the debugger detaches from the process, it decrements all suspend counts by one. When the debugger executes the process, it temporarily decrements all suspend counts by one.
You can control the suspend count of any thread from the debugger by using the following methods:
n (Suspend Thread) command increments the specified thread’s suspend count by one.
m (Resume Thread) command decrements the specified thread’s suspend count by one.
The most common use for these commands is to raise a specific thread’s suspend count from one to two. When the debugger executes or detaches from the process, the thread then has a suspend count of one and remains suspended, even if other threads in the process are executing.
You can suspend threads even when you are performing noninvasive debugging.
The debugger can also freeze a thread. This action is similar to suspending the thread in some ways. However, «frozen» is only a debugger setting. Nothing in the Windows operating system recognizes that anything is different about this thread.
By default, all threads are unfrozen. When the debugger causes a process to execute, threads that are frozen do not execute. However, if the debugger detaches from the process, all threads unfreeze.
To freeze and unfreeze individual threads, you can use the following methods:
f (Freeze Thread) command freezes the specified thread.
u (Unfreeze Thread) command unfreezes the specified thread.
In any event, threads that belong to the target process never execute when the debugger has broken into the target. The suspend count of a thread affects the thread’s behavior only when the debugger executes the process or detaches. The frozen status affects the thread’s behavior only when the debugger executes the process.
Threads and Processes in Other Commands
You can add thread specifiers or process specifiers before many other commands. For more information, see the individual command topics.
You can add the
e (Thread-Specific Command) qualifier before many commands and extension commands. This qualifier causes the command to be executed with respect to the specified thread. This qualifier is especially useful if you want to apply a command to more than one thread. For example, the following command repeats the !gle extension command for every thread that is being debugged.
Multiple Systems
The debugger can attach to multiple targets at the same time. When these processes include dump files or include live targets on more than one computer, the debugger references a system, process, and thread for each action. For more information about this kind of debugging, see Debugging Multiple Targets.
Creating Threads
The CreateThread function creates a new thread for a process. The creating thread must specify the starting address of the code that the new thread is to execute. Typically, the starting address is the name of a function defined in the program code (for more information, see ThreadProc). This function takes a single parameter and returns a DWORD value. A process can have multiple threads simultaneously executing the same function.
The following is a simple example that demonstrates how to create a new thread that executes the locally defined function, MyThreadFunction .
The calling thread uses the WaitForMultipleObjects function to persist until all worker threads have terminated. The calling thread blocks while it is waiting; to continue processing, a calling thread would use WaitForSingleObject and wait for each worker thread to signal its wait object. Note that if you were to close the handle to a worker thread before it terminated, this does not terminate the worker thread. However, the handle will be unavailable for use in subsequent function calls.
The MyThreadFunction function avoids the use of the C run-time library (CRT), as many of its functions are not thread-safe, particularly if you are not using the multithreaded CRT. If you would like to use the CRT in a ThreadProc function, use the _beginthreadex function instead.
It is risky to pass the address of a local variable if the creating thread exits before the new thread, because the pointer becomes invalid. Instead, either pass a pointer to dynamically allocated memory or make the creating thread wait for the new thread to terminate. Data can also be passed from the creating thread to the new thread using global variables. With global variables, it is usually necessary to synchronize access by multiple threads. For more information about synchronization, see Synchronizing Execution of Multiple Threads.
The creating thread can use the arguments to CreateThread to specify the following:
- The security attributes for the handle to the new thread. These security attributes include an inheritance flag that determines whether the handle can be inherited by child processes. The security attributes also include a security descriptor, which the system uses to perform access checks on all subsequent uses of the thread’s handle before access is granted.
- The initial stack size of the new thread. The thread’s stack is allocated automatically in the memory space of the process; the system increases the stack as needed and frees it when the thread terminates. For more information, see Thread Stack Size.
- A creation flag that enables you to create the thread in a suspended state. When suspended, the thread does not run until the ResumeThread function is called.
You can also create a thread by calling the CreateRemoteThread function. This function is used by debugger processes to create a thread that runs in the address space of the process being debugged.