2009-08-14 94 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

相關問題