24
  1. Are .NET threads lightweight user-mode threads or are they kernel-mode operating system threads?

  2. Also, sparing SQL Server, is there a one-to-one correspondence between a .NET thread an an operating system thread?

I am also intrigued because the Thread class that has a symmetric pair of methods named BeginThreadAffinity and EndThreadAffinity, whose documentation subtly suggests that .NET threads are lightweight abstractions over real operating system threads.

Also, I read a while ago on some stack overflow thread itself that Microsoft scratched an attempt to maintain this separation in the CLR, like SQL Server does. There was some project underway to use the Fiber API for this purpose, I recollect, but I can't say I understood all the details of what I read.

I would like some more detailed literature on this topic such as the internal structure of a .NET thread vis-a-vis that of a thread created by Windows. While there is plenty of information available on the structure of a thread created by Windows, Jeffrey Richter's Advanced Windows Programming book being one of the sources, for instance, I can't find any literature dedicated to the internal structure of a .NET thread.

One might argue that this information is available in the .NET source code, which is now publicly available, or using a disassembler such as Reflector or IL Spy, but I don't see anything to represent the Thread Control Block (TCB) and Program Counter (PC) and Stack Pointer (SP) or the thread's wait queue, or the list of queues that the thread is currently a member of in the Thread class.

Where can I read about this? Does the documentation mention any of it? I have read all of these pages from the MSDN but they do not seem to mention it.

Water Cooler v2
  • 32,724
  • 54
  • 166
  • 336
  • 2
    In a normal desktop application, and web application, a .NET thread corresponds to an operating system thread, at least on Windows. In the SQL CLR hosted world, that's not necessarily true, and I have no idea about the .NET core runtime running on other platforms. I don't think a .NET thread is documented to be corresponding to an os kernel thread, this is most likely just an implementation detail. – Lasse V. Karlsen May 27 '16 at 19:30
  • @LasseV.Karlsen Thank you very much. – Water Cooler v2 May 28 '16 at 10:16
  • 2
    @WaterCoolerv2 While Andy's answer is correct it doesnt answer. First part of the question. Check here for some more detailed answer https://stackoverflow.com/questions/49524899/is-the-thread-created-in-c-sharp-user-level-or-kernel-level/51205029#51205029 – kuskmen Jul 14 '18 at 08:13

2 Answers2

15

.NET's threads are indeed abstractions, but you can basically think of them as nearly identical to OS threads. There are some key differences especially with respect to garbage collection, but to the vast majority of programmers (read: programmers who are unlikely to spin up WinDBG) there is no functional difference.

For more detail, read this

Krishna Mohan
  • 1,612
  • 3
  • 19
  • 27
Andy Hopper
  • 3,618
  • 1
  • 20
  • 26
-1

It's important to have some ideas about expected performance and the nature of intended concurrency, before you decide how to do concurrency. For instance, .NET is a virtual machine, so concurrency is simulated. This means more overhead for starting the execution than direct OS threads.

If your application intends to have significant concurrency on demand, .NET tasks or threads (even ThreadPool) will be slow to create and begin executing. In such a case you may benefit from Windows OS threads. However, you'll want to use the unmanaged thread pool (unless you're like me and you prefer writing your own thread pool).

If performance of kicking off an indeterminate number of threads on demand is not a design goal then you should consider the .NET concurrency. The reason is it is easier to program and you can take advantage of keywords impacting concurrency built into the programming language.

To put this into perspective, I wrote a test application that tested an algorithm running in different concurrent units of execution. I ran the test under my own unmanaged thread pool, .NET Tasks, .NET Threads and the .NET ThreadPool.

With concurrency set to 512, meaning 512 concurrent units of execution will be invoked as quickly as possible, I found anything .NET to be extremely slow off the starting block. I ran the test on several systems from an i5 4-core desktop with 16gb RAM to a Windows Server 2012 R2 and the results are the same.

I captured the number of concurrent units of execution completed, how long each unit took to start, and CPU core utilization. The duration of each test was 30 seconds.

All tests resulted in well-balanced CPU core utilization (contrary to the beliefs of some). However, anything .NET would lose the race. In 30 seconds...

.NET Tasks and Threads (ThreadPool) had 34 Tasks completed with an 885ms average start time

All 512 OS Threads ran to completion with a 59ms average start time.

Regardless of what anyone says, the path from invoking an API to start a unit of execution and the actual unit executing, is much longer in .NET.