One of my programs outputs its thread ID for debugging purposes. For testing reasons I'd like to kill the process to which the thread ID belongs.

How do I get the process ID if I have the thread ID so that I can use it with taskkill?

I tried

  • tasklist but it doesn't seem to have a switch for thead IDs.
  • SysInternals Process Explorer's "Find handle" feature, which works, but I'd need something that can be automated in a batch file
  • SysInternals Handle -a Thread, but that doesn't seem to work. handle -a | find "Thread" works better, but I lose the process information
  • Are you willing to write a bit of code for this (like, C++ or C#)? The API you would call is GetProcessIdOfThread, which needs a thread HANDLE; you would get that by calling OpenThread.
    – CBHacking
    Commented Sep 21, 2015 at 9:50
  • @CBHacking: well, if necesary... I thought it must exist out of the box already. Commented Sep 21, 2015 at 9:53
  • I mean, yeah, I'm sure it can be done using sufficiently convoluted regular expressions with findstr or similar. But yeah, tools for Windows don't generally assume you are trying to go from thread ID to process ID; it's usually the other way around.
    – CBHacking
    Commented Sep 21, 2015 at 9:55
  • @CBHacking: No, for sure, if a tool like tid2pid does not exist, I'd rather write one Commented Sep 21, 2015 at 9:57
  • @CBHacking: are you familiar with C++? I added a solution which seems to work for me. Commented Sep 21, 2015 at 12:33

2 Answers 2


You can do it like this with a batch file:

Batchfile killprocess.bat:

@echo off
set processhandle=
set description=
set handle=%1
IF "%handle%." == "." (
  echo Usage: killprocess threadID

FOR /F "tokens=*" %%A IN ('WMIC PATH Win32_thread WHERE handle^=%handle% GET Processhandle /VALUE ^| find "="') DO set "%%A"
FOR /F "tokens=*" %%A IN ('WMIC PATH Win32_process WHERE handle^=%processhandle% GET Description /VALUE ^| find "="') DO set "%%A"

IF "%ProcessHandle%." == "." (
  echo ThreadID not found

echo I'm going to kill %Description% (Processhandle = %processhandle%) if you don't press Q in 5 seconds
echo (or you can press Y to continue)
choice /N /T 5 /C yq /D y
if "%errorlevel%"=="2" goto :eof

echo Killing %Description% (Processhandle = %processhandle%)
Taskkill /PID %processhandle% /T /F

Usage would be something like this:
killprocess 13008

Edit: I also added an abort option (choice) and a description of the process being killed. You could delete this if you don't want it.

  • Edit: I also added an abort option (choice) and a description of the process being killed. You could delete this if you don't want it.
    – Rik
    Commented Sep 21, 2015 at 12:02
  • Great. That works. You were faster than me implementing a C++ solution. Commented Sep 21, 2015 at 12:03
  • Nice solution ;)
    – DavidPostill
    Commented Sep 21, 2015 at 12:05
  • It's possible to DO set "%%A" ? I don't understand how you can call this variable as value
    – Paul
    Commented Sep 21, 2015 at 14:04
  • @Paul %%A contains the complete line ProcessHandle=xxxx which wmic returns. So DO set %%AA will be substituted in DO set ProcessHandle=xxxx which works perfectly. (That way you don't have to split the output of wmic into ProcessHandle and the actual value :))
    – Rik
    Commented Sep 21, 2015 at 14:06

Here's my C++ solution in case anyone wants to use it, I license it as CC0 / public domain. I seldom implement in C++, so forgive mistakes.

#include "stdafx.h"
#include <sstream>
#include <windows.h>
#include <stdio.h>
#include <iostream>
int main(int argc, char* argv[])
    if (argc < 2)
        std::cout << "Usage: " << argv[0] << " <Thread ID>" << std::endl;
        std::cout << "Returns the process ID of a thread." << std::endl;
        std::cout << "Errorlevels:" << std::endl;
        std::cout << "   0 success" << std::endl;
        std::cout << "   1 too few arguments" << std::endl;
        std::cout << "   2 error parsing thread ID" << std::endl;
        std::cout << "   3 error opening thread" << std::endl;
        return 1;

    std::istringstream iss(argv[1]);
    int threadId;

    if (iss >> threadId)
        std::cout << threadId << std::endl;
        HANDLE threadHandle = OpenThread(THREAD_QUERY_INFORMATION, false, (DWORD)threadId);
        if (threadHandle)
            DWORD pid = GetProcessIdOfThread(threadHandle);
            std::cout << pid << std::endl;
            return 0;
        std::cerr << "Error opening thread. Perhaps run as admin or thread does not exist?";
        return 3;
    std::cerr << "Error parsing thread ID. Use decimal, not hex?";
    return 2;
  • 1
    This looks good, yes. The C++ stream silliness (overloading the bit-shift operators) will probably always bother me, but the code appears correct. Could be a little more robust and have better error reporting (for example, check GetLastError() when something goes wrong) but it should work fine.
    – CBHacking
    Commented Sep 21, 2015 at 21:17

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .