2009-08-14 46 views
6

我正在研究一个多线程的C#Windows应用程序,该应用程序会频繁调用本机dll。这些阻止有时会持续相当长时间的呼叫。ManagedThreadID和操作系统之间的关系ThreadID

在某些情况下,我想取消从主线程的一些工作线程这些阻塞调用,我使用的原生API为此提供了一个功能:

HRESULT CancelBlockingCall(DWORD ThreadID) 

虽然文档CancelBlockingCall()不是非常清楚,我相信我需要传递阻塞在调用上的OS级线程的ThreadID。根据我从CancelBlockingCall()得到的返回码,我意识到Thread.ManagedThreadID不是我所需要的。我发现msdn (see the Note)如下:

了操作系统的ThreadId有一个托管线程没有固定的关系,因为 非托管主机可以控制托管和非托管线程之间的关系。 具体而言,复杂的主机可以使用CLR主机API针对相同的操作系统线程安排多个受管理的 线程,或在不同的操作系统线程之间移动受管理的线程。

这是否意味着我无法为托管线程正确调用CancelBlockingCall()?是否无法确定托管线程当前正在执行的OS级别线程的ThreadId?

回答

4

这是否意味着没有办法,我正确地调用CancelBlockingCall()的托管线程?是否无法确定托管线程当前正在执行的OS级别线程的ThreadId?

由于艾丹说,你可以使用GetCurrentThreadID API来获取操作系统的线程ID。

为了保持它的轨道跨越托管线程,你可以换你的API调用您存储操作系统的线程ID的一类,这样就可以在以后停止:

public class APITask 
{ 
    private uint _osThreadId; 

    public void Run() 
    { 
     _osThreadId = GetCurrentThreadID(); 
     API.RunBlockingMethod(); 
    } 

    public void Cancel() 
    { 
     API.CancelBlockingCall(_osThreadId); 
    } 
} 
2

你可以尝试P /调用API GetCurrentThreadID

+0

为什么选择P/Invoke?为什么不'AppDomain.GetCurrentThreadId'? – Gabe 2012-03-01 06:39:22

0

有关使用Abortable ThreadPool如何?

来自文章;

取而代之的是,考虑一个线程池实现,它将一个排序的工作项目的cookie传回给您。然后,池可以提供一个Cancel方法,该方法将取得这些cookie中的一个并取消相关的工作项,将其从队列中移除或根据需要中止正在执行的工作项。实现自定义线程池这个任务可能不是最好的办法,但也有其他的替代品

13

正如其他人所提到的,你可以尝试P /调用阻塞的原始功能和地方注册这个ID之前调用GetCurrentThreadId ,但这是一个时间炸弹 - 有一天,您的托管线程将被抢先重新安排到两个p/invoke调用之间的另一个OS级线程。我建议的唯一可靠的方法是编写一个小型非托管代理dll,它将首先调用GetCurrentThreadId(将其写入out IntPtr某处,托管代码可以看到它),然后调用本机阻塞函数。回调到托管代码而不是out IntPtr也可能会工作;当堆栈中存在非托管框架时,CLR几乎不能重新调度线程。

编辑:显然你不是有这样的问题的第一人:有在System.Threading.Thread 2的便利方法,允许一个化解我提到的定时炸弹和P/Invoke的GetCurrentThreadId()Thread.BeginThreadAffinity()Thread.EndThreadAffinity()。 CLR主机不会将托管线程重新安排到这些调用之间的其他本地线程。尽管如此,您的代码需要以较高的信任级别运行以调用这些方法。

+0

+1用于突出上述方法的风险 – Odrade 2009-08-15 12:49:44

+0

是的,好点! – 2009-08-15 15:35:39

+0

感谢您的更新。如果我能再次让你高兴,我会的。 – Odrade 2009-08-20 17:06:15

相关问题