9

As an exercise I was writing some code to display the O/S processes and O/S threads within a process (like Sysinternals process explorer does).

I found that .net's ManagedThreadId(s) are not the O/S thread ids. After a bit of reading I came across AppDomain.GetCurrentThreadId(). Unfortunately, that function is marked as "obsolete" (which could mean "not available" in the future). One solution I found is to use InteropServices to directly call the Win32 GetCurrentThreadId. I am fine with that but, it feels counter to the .net philosophy.

My question is: is there a CLR "friendly" way of obtaining the real id of the current thread ?

For reference, here is a snippet of code showing what I've tried so far. // 1 and // 2 display the correct thread id, // 3 and // 4 were attempts to obtain the same info in a CLR friendly way (but they don't work.)

Thank you for your help,

John.

[DllImport("kernel32.dll")]
static extern int GetCurrentThreadId();

static void Main(string[] args)
{
  // AppDomain.GetCurrentThreadId() is "obsolete"

  int ThreadId1 = AppDomain.GetCurrentThreadId();   // 1 

  // not the ".net" way of doing things

  int ThreadId2 = GetCurrentThreadId();             // 2 

  // "no joy" attempts to get the same results I got above

  int ThreadId3 = Process.GetCurrentProcess().Threads[0].Id;   // 3
  int ThreadId4 = Thread.CurrentThread.ManagedThreadId;        // 4


  Console.WriteLine("ThreadId1: {0}, ThreadId2: {1}, ThreadId3: {2}, " + 
                    "ThreadId4: {3}",
                    ThreadId1, ThreadId2, ThreadId3, ThreadId4);
}
Hex440bx
  • 657
  • 6
  • 16
  • 2
    Why would you want a CLR "Friendly" way for getting a piece of CLR "unfriendly" data over which you can only execute CLR "unfriendly" operations? – Polity Apr 11 '11 at 16:07
  • @Polity: I write system utilities and most of them have nothing to do with .net. If I program in .net, I'd like to be "friendly" to .net even if the information I'm interested in is unrelated to the .net environment. – Hex440bx Apr 11 '11 at 16:14
  • Well,my point stays valid :) there is no reason to build part of a car from steel and the other part from wood. Just like there is no reason to get a native threadID i a .NET friendly way only to use it with native system API's. Using win32's GetCurrentThreadId is perfectly valid in this case! – Polity Apr 11 '11 at 16:29
  • Might be a duplicate of [this question](http://stackoverflow.com/questions/466632/how-can-i-get-managed-threads-from-process-getcurrentprocess-threads). – Szymon Rozga Apr 11 '11 at 16:05

3 Answers3

11

PInvoking into the GetCurrentThreadId is your best bet and will give you the correct information.

However I must warn you, there are very good reasons why the CLR doesn't provide this information: it's almost a completely useless value for managed code. It's perfectly legal from a CLR perspective for a single managed thread to be backed by several different native threads during it's lifetime. This means the result of GetCurrentThreadId can (and will) change throughout the course of a thread's lifetime.

In many applications this is not an observable phenomenon. In a UI application this won't actually happen because it's typically backed by an STA thread which is harder (usually even illegal) to swap out due to COM interop issues. So many developers are blissfully ignorant of this. However it's very easy to swap out MTA threads under the hood which is typically the execution context of a background thread.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • thank you. I am aware of the difference between the .net threads and the O/S threads (that's why I mentioned Sysinternals' Process Explorer). From your reply I gather that there is no CLR way of getting the O/S' current thread other than PInvoking. I will wait for other suggestions before choosing an answer. – Hex440bx Apr 11 '11 at 16:09
  • @Hex440bx I'm fairly certain that every way to get the native id from managed code was deprecated in 2.0. – JaredPar Apr 11 '11 at 16:12
-1

It's obsolete for a reason; the idea being in the future the 'actual' thread ID might not be constant, or might be shared between .NET threads.

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
  • @Kieren: I am not going to the info to "manipulate" something in .net, I will use it only at the O/S level (like Process Explorer does, for instance.) – Hex440bx Apr 11 '11 at 16:17
  • The contradiction seems to be you're looking for the current thread ID, which has the problems I mention above; the point is one .NET thread is not necessarily equal to one O/S thread – Kieren Johnstone Apr 11 '11 at 16:20
  • @Kieren: I understand your point about the .net and O/S threads. What I am saying is, if I wanted to write an utility such as Process Explorer using C# (and .net obviously), could it be done staying true to the .net philosophy while providing information that is accurate at the O/S level. – Hex440bx Apr 11 '11 at 16:24
  • Then why are you calling GetCurrentThread, GetCurrentProcess etc - that's all to do with managed threads? Don't you mean to enumerate regular processes/threads (which will work without any of the problems)? – Kieren Johnstone Apr 11 '11 at 16:26
  • @Kieren: because (like Process Explorer) I am interested in what is happening at the O/S level not what is happening in .net. In this case, .net is the means to get the information but not the end (the end being the O/S and its state) – Hex440bx Apr 11 '11 at 16:38
  • But WHY for the *CURRENT* *THREAD* ? (i.e. a MANAGED thread not a NATIVE one) – Kieren Johnstone Apr 11 '11 at 16:45
  • @Kieren: simply because I wanted to determine what the current O/S thread is/was. – Hex440bx Apr 11 '11 at 16:56
-2

I don't understand why people ask "why don't you ...". The question was how to get the REAL (operating system) thread id. And there is an important reason for it, which derives from Visual Studio itself ... it reports the ending of a thread not with the managed id, but obviously with the operating system thread id (e.g. "The Thread 0x5424 has ended with Code 0 (0x0)."). To be able to trace/follow the thread usages and endings fully, to verify your thread handling perfectly, e.g. on asynchronous methods, which return on newly created threads [e.g. TCPListener.BeginAccept => new Socket on new thread], you NEED the native thread id. After having studied as many answers about this problem as possible, in many blogs, it seems for me, as if the only reliable method to retrieve the native id of the current thread is by:

[DllImport("Kernel32", EntryPoint = "GetCurrentThreadId", ExactSpelling = true)]

public static extern Int32 GetCurrentWin32ThreadId();

...

int nativeThreadID = GetCurrentWin32ThreadId();

Tom Ernst
  • 11
  • 2
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31311273) – MD. RAKIB HASAN Mar 21 '22 at 07:15