Search code examples
c#multithreadingprocessprocess-explorer

Process.Threads does not contain the full list of threads spawned by a process


My application starts a secondary Process (an exe file stored in the filesystem). This Process then spawns several Threads that perform long operations multicore.

I can see from ProcessExplorer the list of threads started by this Process:

enter image description here

In yellow, the Process that my application started, in red the "long" threads that this Process started by itself (note that their addresses starts from a DLL!).

In my C# code, I expect to see all of these threads using myprocess.Threads property (where myprocess is the Process started by my app). Instead, I see thread ID 18160 and others, but not the ones highlighted in red. Why?

In general, as you see from the image the total count of threads is 43, while the size of myprocess.Threads is 30.


Solution

  • The implementation of Process.Threads returns all threads associated with this process, but they might be threads that are not necessarily owned by this process.

    Process.Threads uses CreateToolHelp32Snapshot to collect the information on Win32. The documentation of CreateToolHelp32Snapshot says:

    To identify the threads that belong to a specific process, compare its process identifier to the th32OwnerProcessID member of the THREADENTRY32 structure when enumerating the threads.

    The code that populates Process.Threads, however, doesn't check th32OwnerProcessID; it simply enumerates all threads. You can see the code here:

    if (NativeMethods.Thread32First(handleRef, thread)) 
    {
        do 
        {
           ThreadInfo threadInfo = new ThreadInfo();
           threadInfo.threadId = thread.th32ThreadID;
           threadInfo.processId = thread.th32OwnerProcessID;
           threadInfo.basePriority = thread.tpBasePri;
           threadInfo.currentPriority = thread.tpBasePri + thread.tpDeltaPri;
           threadInfos.Add(threadInfo);
        }
        while (NativeMethods.Thread32Next(handleRef, thread));
    }
    

    So, I assume you also see threads that are owned by other processes, but associated with your child process.