Relationship between ManagedThreadID and ThreadID Operating System

I am working on a multi-threaded Windows C # application that often causes calls to the native dll. These are blocking calls that can sometimes last quite a while.

In some situations, I would like to cancel these blocking calls to some worker threads from the main thread. The native API that I use provides a function for this purpose:

HRESULT CancelBlockingCall(DWORD ThreadID) 

Although the documentation for CancelBlockingCall () is not very clear, I believe that I need to pass ThreadID to an OS-level thread that blocks the call. Based on the return codes I get from CancelBlockingCall (), I realized that Thread.ManagedThreadID is not what I need. I found the following in msdn (see note) :

The ThreadId operating system does not have a fixed relationship with a managed thread, because an unmanaged host can control the relationship between managed and unmanaged threads. In particular, a complex 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 for me there is no way to correctly call CancelBlockingCall () on a managed thread? Is it impossible to determine ThreadId in the OS level thread in which the managed thread is currently running?

+6
multithreading c # windows
Aug 14 '09 at 20:13
source share
4 answers

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

As Aidan said, you can use the GetCurrentThreadID API to get the OS thread id.

To track this through managed threads, you can wrap the API calls in a class where you store the OS thread id so you can stop it later:

 public class APITask { private uint _osThreadId; public void Run() { _osThreadId = GetCurrentThreadID(); API.RunBlockingMethod(); } public void Cancel() { API.CancelBlockingCall(_osThreadId); } } 
+4
Aug 14 '09 at 20:27
source share

As mentioned by other people, you can try p / invoking GetCurrentThreadId before calling the lock function and register this identifier somewhere, but this is a temporary bomb - at some point your managed thread will be previously missed and reassigned to another OS-level thread between two calls to p / invoke. The only reliable way I can offer is to write a small unmanaged dll proxy library that will call GetCurrentThreadId first (writing it to out IntPtr somewhere where it will be visible to the managed code), and then your own lock function. Managed code callbacks instead of out IntPtr can also work; The CLR is unlikely to be able to reallocate threads as long as there are unmanaged frames on the stack.

Edit: Apparently, you are not the first person to have such problems: System.Threading.Thread has two convenient methods that allow you to defuse the temporary bomb you mentioned and p / invoke GetCurrentThreadId() : Thread.BeginThreadAffinity() and Thread.EndThreadAffinity() . The CLR host does not reschedule the managed thread to another native thread between these calls. However, your code must run at a high level of trust to call these methods.

+13
Aug 15 '09 at 11:28
source share

You can try the P / Call GetCurrentThreadID API

+2
Aug 14 '09 at 20:17
source share

How about using Abortable ThreadPool ?

From the article;

Instead, consider implementing a thread pool that returned cookies to you for a given work item. The pool can then also provide a Cancel method that would take one of these cookies and cancel the associated work item by removing it from the queue or interrupting the corresponding work item. Implementing a custom thread pool for this task is probably not a good idea, but there are other alternatives.

0
Aug 15 '09 at 11:16
source share



All Articles