2

I want to count native threads of the current Windows process via C/C++. I see there's a related question with a .NET answer, but I can't use that solution. I suspect that there may be a solution via PdhOpenQuery/PdhCollectQueryData but I haven't explored that direction yet, and I'm hoping there's an easier approach.

UPDATE: I should have said that my current implementation uses CreateToolhelp32Snapshot/Thread32First/Thread32Next and that's what I'm trying to replace. That implementation is heavy-handed and causes 20,000 page faults on every invocation in my process. Maybe I'm just using it wrong?

Update2: The solution that worked best for me was to make a string like "\Process(_)\Thread Count" with the PID of the process I was interested in. Then I called PdhExpandWildCardPath() to expand the "" wildcard. Then I invoked PdhOpenQuery(), PdhAddCounter() and PdhCollectQueryData() to initialize. Thereafter, I called PdhCollectQueryData() and PdhGetFormattedCounterValue() to get my values periodically.

Community
  • 1
  • 1
Chris Dolan
  • 8,905
  • 2
  • 35
  • 73

2 Answers2

3

EDIT the second: Your text says "current process". If that is really the case, you could implement a small DLL whose DllMain maintains an active thread counter using InterlockedDecrement (on DLL_THREAD_DETACH) and InterlockedIncrement (on DLL_THREAD_ATTACH).

You would have to make sure your process loads up this DLL early on so the thread count starts at 1 for our main thread. Then your thread count is always up to date and quickly accessible via the Interlocked* APIs.

EDIT: For improved performance, you could access the PerfMon counters for your process and get the thread count for a given process in one shot. There is VB code here that you could model off of.

You could also use WMI to enumerate threads by process but this is hardly an easy programming model.

PerfMon will be the fastest.

ORIGINAL: Raymond Chen has exact instructions for this here. Just need to filter by process ID matching your own (obtained via GetCurrentProcessId) in the condition before the printf.

#include <stdio.h>
#include <windows.h>
#include <tlhelp32.h>

int __cdecl main(int argc, char **argv)
{
 HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
 if (h != INVALID_HANDLE_VALUE) {
  THREADENTRY32 te;
  te.dwSize = sizeof(te);
  if (Thread32First(h, &te)) {
   do {
     if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) +
                      sizeof(te.th32OwnerProcessID)) {
       printf("Process 0x%04x Thread 0x%04x\n",
             te.th32OwnerProcessID, te.th32ThreadID);
     }
   te.dwSize = sizeof(te);
   } while (Thread32Next(h, &te));
  }
  CloseHandle(h);
 }
 return 0;
}
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • 1
    Thanks, I just updated the question to indicate that your solution is what I'm using currently today, but I'm looking for something more performant. Or maybe I'm too worried about the page fault consequences of this solution? – Chris Dolan Nov 11 '10 at 16:31
  • @Chris - see edit - Perfmon typically uses shared memory and this should be quick. – Steve Townsend Nov 11 '10 at 16:40
  • Steve, thanks for the DLL_THREAD_DETACH idea. This code has to run as a late-loading DLL under a JVM process, so that won't fly. I'm trying the PDH solution now... – Chris Dolan Nov 11 '10 at 17:56
  • If this CreateToolhelp32Snapshot approach isn't useful to OP because of the 2000 page faults, why is this answer an "accepted" one? – Jayanth Jan 22 '23 at 10:37
1

The ToolHelp API provides a set of functions to enumerate the threads. Using Thread32First and Thread32Next you can count.

harper
  • 13,345
  • 8
  • 56
  • 105