【问题标题】:How to get the main thread ID of a process (known by its ID)?如何获取进程的主线程 ID(通过其 ID 知道)?
【发布时间】:2013-03-13 21:17:24
【问题描述】:

您能帮我找到由 ID 进程给定的主(唯一)线程 ID,好吗?

任务上下文: 一个正在运行的进程(目前)没有窗口,只有一个(一些)线程。

想要: 仅在主线程发布WM_QUIT

不想要的: 在非主线程使用TerminateProcess 或发布WM_QUIT

【问题讨论】:

    标签: c++ c windows multithreading


    【解决方案1】:

    您不能将消息发布到特定线程。消息被放入队列中,并且仅从主线程处理。

    如果您想关闭具有 UI 的 windows 进程,请查看using sendmessage to send wm_close to another process

    【讨论】:

    • 其实可以有多个消息队列,每个消息队列关联不同的线程,如果有,可以使用 PostThreadMessage 向特定线程发送消息。
    • @Harry:知道这很有趣!当存在多个队列时,实际用例是什么?
    • 我相信如果你从一个线程调用MessageBox,而不指定一个父窗口,相关的窗口消息是从那个线程处理的。您也可以将消息队列用于线程之间的内部消息传递,尽管我个人更喜欢 APC。
    • -1 由于错误/误导“无法发布到特定线程” - 是的,你可以 - q.v. PostThreadMessage。实际上,如果 Win32 提供 PostProcessMessage 并且您的假设是正确的(或者至少为此目的以这种方式工作),这会容易得多。但唉,不是这样......
    【解决方案2】:
    #ifndef MAKEULONGLONG
    #define MAKEULONGLONG(ldw, hdw) ((ULONGLONG(hdw) << 32) | ((ldw) & 0xFFFFFFFF))
    #endif
    
    #ifndef MAXULONGLONG
    #define MAXULONGLONG ((ULONGLONG)~((ULONGLONG)0))
    #endif
    
    bool CloseProcessMainThread(DWORD dwProcID)
    {
      DWORD dwMainThreadID = 0;
      ULONGLONG ullMinCreateTime = MAXULONGLONG;
    
      HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
      if (hThreadSnap != INVALID_HANDLE_VALUE) {
        THREADENTRY32 th32;
        th32.dwSize = sizeof(THREADENTRY32);
        BOOL bOK = TRUE;
        for (bOK = Thread32First(hThreadSnap, &th32); bOK;
             bOK = Thread32Next(hThreadSnap, &th32)) {
          if (th32.th32OwnerProcessID == dwProcID) {
            HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION,
                                        TRUE, th32.th32ThreadID);
            if (hThread) {
              FILETIME afTimes[4] = {0};
              if (GetThreadTimes(hThread,
                                 &afTimes[0], &afTimes[1], &afTimes[2], &afTimes[3])) {
                ULONGLONG ullTest = MAKEULONGLONG(afTimes[0].dwLowDateTime,
                                                  afTimes[0].dwHighDateTime);
                if (ullTest && ullTest < ullMinCreateTime) {
                  ullMinCreateTime = ullTest;
                  dwMainThreadID = th32.th32ThreadID; // let it be main... :)
                }
              }
              CloseHandle(hThread);
            }
          }
        }
    #ifndef UNDER_CE
        CloseHandle(hThreadSnap);
    #else
        CloseToolhelp32Snapshot(hThreadSnap);
    #endif
      }
    
      if (dwMainThreadID) {
        PostThreadMessage(dwMainThreadID, WM_QUIT, 0, 0); // close your eyes...
      }
    
      return (0 != dwMainThreadID);
    }
    

    【讨论】:

    • 这个答案如果包含一些关于代码的作用和工作原理的解释会更好。特别是,在某个进程有多个线程的情况下,您如何确定该进程的“主”线程是什么?在我看来,您是基于线程的创建时间。这不一定是可靠的启发式方法。重要的是指出人们可以仔细考虑这种方法的优点和缺点。包含only代码的答案不是答案。
    【解决方案3】:

    获取主线程的线程 id 一个更简单、更可靠的方法是让主线程使用::GetCurrentThreadId() 将自己的线程 id 记录到一个共享的全局变量中,可能在您的 WinMain 中或在开头的某个地方你的“主线程”:

    MainThreadId_G = ::GetCurrentThreadId();
    

    然后在你的其他线程中,你可以调用:::PostThreadMessage(MainThreadId_G, WM_QUIT, returncode, 0);

    【讨论】:

    • 我绝对喜欢这个答案。简洁,提供完整的答案和很好的解释。当然,可以在创建工作线程时将主线程 ID 作为参数传递给工作线程,而不是使用全局变量。
    • @MarkCh 除了创建者线程本身可能是工作线程或其他一些工作任务等,它们本身可能不是主线程ID。更不用说所有的簿记和开销,而不仅仅是拥有一个全局。当然,全局可能对静态/动态链接库不可见,从而增加了复杂性。
    【解决方案4】:

    我检查了 MFC 中是如何处理的,看起来 UI 线程是由构造函数确定的:

    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\atlmfc\src\mfc\appcore.cpp:
    
    CWinApp::CWinApp(LPCTSTR lpszAppName)
    {
    ...
    
        m_nThreadID = ::GetCurrentThreadId();
    

    并且使用 MFC 调用 AfxGetApp()-&gt;m_nThreadID 您可以找出 UI 线程 ID。

    但是 - 如果 .dll 不是从主线程加载,则此方法不起作用 - 然后即使 MFC 的方法也不起作用 - AfxGetApp()-&gt;m_nThreadID 将返回主线程以外的其他内容。

    但通常您的 .dll 是从主线程加载的,但您的 .dll 不需要启用 mfc。我可以推荐这样的方法:

    class GetMainThread
    {
    public:
        GetMainThread()
        {
            m_nThreadID = ::GetCurrentThreadId();
        }
    
        DWORD m_nThreadID;
    }getMainThread;
    
    
    DWORD getUIThread()
    {
        DWORD id = 0;
    
        if( AfxGetApp() != NULL )
            id = AfxGetApp()->m_nThreadID;
        else 
            id = getMainThread.m_nThreadID;
    
        return id;
    } //getUIThread
    

    如果 .dll 由主 UI 线程加载,您将从构造函数调用(GetMainThread 类)中获得正确的线程 ID。

    如果您不需要它们,请删除 AfxGetApp() 调用(在我的应用程序中我需要它们)

    【讨论】:

      【解决方案5】:

      你是否在寻找这个功能:

      DWORD WINAPI GetProcessIdOfThreadId(_In_ DWORD ThreadId)
      {
          HANDLE Thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, ThreadId);
          DWORD process_id = GetProcessIdOfThread(Thread);
          CloseHandle(Thread);
          return process_id;
      }
      

      【讨论】:

        【解决方案6】:

        在 cpp 文件的开头使用它,而不是在函数中:

        DWORD mainThreadID = ::GetCurrentThreadId();
        

        这将在你的 main 函数被执行之前初始化 mainThreadID,保证是主线程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-07-27
          • 1970-01-01
          • 2021-03-25
          • 1970-01-01
          • 2014-06-27
          • 2018-12-08
          • 1970-01-01
          相关资源
          最近更新 更多