Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
196 views
in Technique[技术] by (71.8m points)

c# - Relationship between ManagedThreadID and Operating System ThreadID

I'm working on a multi-threaded C# Windows application that makes frequent calls into a native dll. These are blocking calls which can sometimes last quite a long time.

In certain situations, I'd like to cancel these blocking calls on some worker threads from the main thread The native API I'm using provides a function for this purpose:

HRESULT CancelBlockingCall(DWORD ThreadID)

Although the documentation for the CancelBlockingCall() isn't terribly clear, I believe I need to pass the ThreadID for the OS-level thread which is blocking on the call. Based on the return codes I'm getting from CancelBlockingCall(), I realized that Thread.ManagedThreadID is not what I need. I found the following on msdn (see the Note):

An operating-system ThreadId has no fixed relationship to a managed thread, because an unmanaged host can control the relationship between managed and unmanaged threads. Specifically, a sophisticated host can use the CLR Hosting API to schedule many managed threads against the same operating system thread, or to move a managed thread between different operating system threads.

Does this mean that there is no way for me to properly call CancelBlockingCall() for a managed thread? Is it impossible to determine the ThreadId of the OS-level thread in which a managed thread is currently executing?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As other people mentioned, you could try p/invoking GetCurrentThreadId before calling the blocking native function and registering that id somewhere, but this is a timebomb — some day your managed thread will get pre-empted and re-scheduled to a different OS-level thread between the two p/invoke calls. The only reliable way I can suggest is to write a tiny unmanaged proxy dll, which will call first GetCurrentThreadId (writing it into an out IntPtr someplace where it will be visible to managed code) and then your native blocking function. A callback into managed code instead of out IntPtr might work too; CLR can hardly re-schedule threads while there are unmanaged frames on the stack.

Edit: apparently you're not the first person to have such problems: there are two handy methods in System.Threading.Thread which allow one to defuse the timebomb I mentioned and p/invoke GetCurrentThreadId(): Thread.BeginThreadAffinity() and Thread.EndThreadAffinity(). CLR host will not re-schedule a managed thread to a different native thread between these calls. Your code needs to run at a high trust level to call these methods, though.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...