From: Tony Johansson on
Hello!

If I run the program below will the ManagedThreadId start counting from 3 so
the output in SimpleWork is like this.
So why will the ManagedThreadId start counting from 3 ?
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5
Thread: 3
Thread: 4
Thread: 5

static void Main(string[] args)
{
ThreadStart operation = new ThreadStart(SimpleWork);
for (int x = 1; x <= 3; x++)
{
Thread theThread = new Thread(operation);
theThread.Start();
}
}

private static void SimpleWork()
{
for (int x = 1; x <= 10; x++)
{
Console.WriteLine("Thread: {0}",
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}
}

//Tony


From: Peter Duniho on
Tony Johansson wrote:
> Hello!
>
> If I run the program below will the ManagedThreadId start counting from 3 so
> the output in SimpleWork is like this.
> So why will the ManagedThreadId start counting from 3 ?

Hint: the threads you created aren't the only threads in your process.
In fact, you can't create a new thread unless there's already at least
one running. And in actuality, .NET creates other threads for its own
use before your own code gets a chance to start creating new ones.

But beyond all that, there is absolutely no guarantee whatsoever that
the ManagedThreadId property is anything other than a unique identifier
for a Thread instance. It may be interesting in an academic sort of way
to note that the numbers appear to be assigned incrementally, but for
all .NET promises you, they could be completely random.

Asking why the ManagedThreadId property values don't fit your particular
expectation of ordering, initialization, or whatever makes no sense.
Each Thread instance can have any ManagedThreadId .NET wants it to have,
so long as no other Thread instance has that ManagedThreadId.

Pete
From: Arne Vajhøj on
On 18-06-2010 03:03, Tony Johansson wrote:
> If I run the program below will the ManagedThreadId start counting from 3 so
> the output in SimpleWork is like this.
> So why will the ManagedThreadId start counting from 3 ?
> Thread: 3
> Thread: 4
> Thread: 5

Maybe one for main thread and one for GC.

Arne
From: kndg on
On 6/21/2010 10:09 AM, Arne Vajh�j wrote:
> On 18-06-2010 03:03, Tony Johansson wrote:
>> If I run the program below will the ManagedThreadId start counting
>> from 3 so
>> the output in SimpleWork is like this.
>> So why will the ManagedThreadId start counting from 3 ?
>> Thread: 3
>> Thread: 4
>> Thread: 5
>
> Maybe one for main thread and one for GC.
>
> Arne

Hi Arne,

Actually, this had drove me crazy, but since you had mentioned it, I
would like to share my own findings (though not actually related to the
main discussion).
When I read this post, I tried to calculate how many threads a process
had initially created. For a native Win32 console, there is only one
thread which is understandable and for a native window application,
there are two threads created which is also understandable (extra thread
is for the GUI).
For a .Net console application, there are at minimum four threads
created. So, here is my own guess (I couldn't find a source on the
internet to confirm this)

1. Native Win32 thread hosting the CLR
2. CLR (JIT, Assembly Loader and GC?)
3. ? or GC?
4. Primary AppDomain main thread

Actually, at first I thought that the GC would be on the same thread as
the CLR thread and left the third mysteriously unknown (to myself), but
after researching on the internet, I found that the GC is actually
running concurrently and running on their own thread and that fills my
mysterious thirds thread. And since you had mentioned it, it probably
affirms my own guess.

A .Net windows application create one extra thread to service the GUI,
but a .Net WPF appication create a whopping 10 threads total (probably
for marshalling and communicating with native DirectX library).

Application Thread Count
--------------------------------
Native Win32 Console 1
Native Win32 Window 2
..Net Console 4
..Net Window 5
..Net WPF 10

If someone could point out to the correct info or source, I would be
highly appreciated. Is it for my own understanding the internal working
of .Net process.

Regards.
From: Peter Duniho on
kndg wrote:
> On 6/21/2010 10:09 AM, Arne Vajh�j wrote:
>> On 18-06-2010 03:03, Tony Johansson wrote:
>>> If I run the program below will the ManagedThreadId start counting
>>> from 3 so
>>> the output in SimpleWork is like this.
>>> So why will the ManagedThreadId start counting from 3 ?
>>> Thread: 3
>>> Thread: 4
>>> Thread: 5
>>
>> Maybe one for main thread and one for GC.
>>
>> Arne
>
> Hi Arne,
>
> Actually, this had drove me crazy, but since you had mentioned it, I
> would like to share my own findings (though not actually related to the
> main discussion).
> When I read this post, I tried to calculate how many threads a process
> had initially created. For a native Win32 console, there is only one
> thread which is understandable and for a native window application,
> there are two threads created which is also understandable (extra thread
> is for the GUI).

Actually, there's no reason for an unmanaged (native) GUI program to
have more than one thread, assuming _only_ a dependency on the plain
Win32 GUI API. A GUI does not in and of itself imply an additional
thread; typically, the GUI executes in the same thread that the
process's initial entry point used.

A GUI application that uses COM components, especially those that are
free-threaded (i.e. use the multi-threaded apartment) may result in a
new thread started up by COM, because typically COM is initialized in
the main GUI thread as an STA thread. But even that will vary according
to the exact program.

You _might_ also see one or more extra threads if running the process
under a debugger. But that's just an artifact of debugging.

> For a .Net console application, there are at minimum four threads
> created. So, here is my own guess (I couldn't find a source on the
> internet to confirm this)
>
> 1. Native Win32 thread hosting the CLR
> 2. CLR (JIT, Assembly Loader and GC?)
> 3. ? or GC?
> 4. Primary AppDomain main thread

The first thing to understand is that a native thread may or may not be
the same as a managed thread. So when counting threads, it's important
to make sure one is specific about which kind of thread one is talking
about.

For example, in the above list, the "primary AppDomain main thread" is a
managed thread, while the "native Win32 thread hosting the CLR" is by
definition unmanaged.

Beyond that, I would not expect the above list to be accurate even on
..NET implementations where a managed thread corresponds exactly to an
unmanaged thread. In particular, the main thread for the managed
process is as far as I know the same as the main thread for the process.
There's certainly no obvious reason for it not to be, and even running
under the debugger (*), a .NET console app has only one non-worker thread.

(*) where at least one additional thread is created as part of the
hosting mechanism�I did a test with a simple WPF application, which when
debugging had 6 threads without the debugger's host process and 13 with;
running standalone, it had only 5 threads

> Actually, at first I thought that the GC would be on the same thread as
> the CLR thread and left the third mysteriously unknown (to myself), but
> after researching on the internet, I found that the GC is actually
> running concurrently and running on their own thread and that fills my
> mysterious thirds thread. And since you had mentioned it, it probably
> affirms my own guess.

The GC can be run concurrently or not, depending on .NET implementation
and configuration.

> A .Net windows application create one extra thread to service the GUI,
> but a .Net WPF appication create a whopping 10 threads total (probably
> for marshalling and communicating with native DirectX library).

Neither marshaling nor using DirectX actually requires additional
threads, or is even done more effectively with additional threads.

It's entirely possible that the extra threads seen are simply a result
of WPF using the thread pool more heavily, and thus causing more worker
threads to be started. If you watch the process long enough, you may
find the total thread count goes down, as the thread pool expires threads.

Or they could be there for some completely different reason.

I don't actually know what all the different threads .NET and its
various components may create on the behalf of the process actually do.
The fact is, it's not something I worry about very much. The exact
thread count for a managed process is even more of an "implementation
detail" than for an unmanaged process, and even the unmanaged process
has some specific scenarios where you might get a thread or two in your
process you didn't explicitly create.

The main take-away should simply that thread IDs are not guaranteed to
be anything other than a unique way to identify a thread (i.e. they
aren't necessarily even consecutive, never mind start at 0). Even if it
can be explained why the thread IDs are distributed in a certain way to
today, that information is purely academic and subject to change in the
next revision of .NET.

Pete