代码之家  ›  专栏  ›  技术社区  ›  Odrade

ManagedThreadID和操作系统ThreadID之间的关系

  •  7
  • Odrade  · 技术社区  · 17 年前

    在某些情况下,我希望从主线程取消对某些工作线程的这些阻塞调用。我使用的本机API为此提供了一个函数:

    HRESULT CancelBlockingCall(DWORD ThreadID)
    

    尽管CancelBlockingCall()的文档并不十分清楚,但我认为我需要传递操作系统级线程的ThreadID,该线程正在阻塞调用。根据从CancelBlockingCall()获得的返回代码,我意识到Thread.ManagedThreadID不是我所需要的。我在网上发现了以下内容 msdn (see the Note) :

    操作系统线程ID与托管线程没有固定关系,因为 非托管主机可以控制托管线程和非托管线程之间的关系。 具体地说,一个复杂的主机可以使用CLR宿主API来调度许多托管API 针对同一操作系统线程的线程,或在两个线程之间移动托管线程 不同的操作系统线程。

    这是否意味着我无法为托管线程正确调用CancelBlockingCall()?是否无法确定当前正在执行托管线程的操作系统级线程的线程ID?

    4 回复  |  直到 17 年前
        1
  •  14
  •   Anton Tykhyy    17 年前

    正如其他人提到的,您可以尝试p/invoking GetCurrentThreadId 在调用阻塞本机函数并在某个地方注册该id之前,但这是一个定时炸弹。有朝一日,托管线程将被抢占,并在两个p/invoke调用之间重新调度到不同的OS级线程。我建议的唯一可靠的方法是编写一个小型的非托管代理dll,它将首先调用 (将其写入 out IntPtr 输出IntPtr

    编辑: 显然,你不是第一个遇到这种问题的人:有两种简便的方法 System.Threading.Thread GetCurrentThreadId() Thread.BeginThreadAffinity() 和 Thread.EndThreadAffinity() . CLR主机不会在这些调用之间将托管线程重新调度到不同的本机线程。但是,您的代码需要在高信任级别上运行才能调用这些方法。

        2
  •  4
  •   Thomas Levesque    9 年前

    正如艾丹所说,你可以使用 GetCurrentThreadID 获取操作系统线程ID的API。

    public class APITask
    {
        private uint _osThreadId;
    
        public void Run()
        {
            _osThreadId = GetCurrentThreadID();
            API.RunBlockingMethod();
        }
    
        public void Cancel()
        {
            API.CancelBlockingCall(_osThreadId);
        }
    }
    
        3
  •  2
  •   Aidan Ryan    17 年前

    您可以尝试P/调用 GetCurrentThreadID 美国石油学会

        4
  •  0
  •   gts    17 年前

    使用如何 Abortable ThreadPool ?

    从文章中;

    相反,考虑一个线程池实现,它为您返回队列工作项中的一类cookie。然后,该池还可以提供一个Cancel方法,该方法将获取其中一个cookie并取消关联的工作项,将其从队列中删除,或者根据需要中止正在执行的工作项。为这个任务实现一个自定义线程池可能不是最好的主意,但是还有其他的选择

    推荐文章