Between three types of threading (kernel-level, user-level and hybrid), which type does C# (or more generally .NET) use?
The term "kernel threads" can be used to refer to actual threads that run entirely in kernel space or it can refer to user-space threads scheduled by the kernel. The term "kernel-supported" threads means the latter, threads that run in user-space but are facilitated by the kernel, which usually means the kernel schedules them.
Kernel threads are privileged and can access things off-limits to user mode threads. Take a look at "Ring (Computer Security)" on Wikipedia. On Windows, user mode corresponds to Ring 3, while kernel mode corresponds to Ring 0.
"User-level threads" usually means threads visible to user space. That is, what you create when you call your threading standard's "create thread" function. Generally, the term "user-level thread" is used to mean a thread created by the application code regardless of how it's implemented by the system. It may be a pure user-space thread with little to no kernel support or it may be a thread scheduled by the kernel.
M:N maps some M number of application threads onto some N number of kernel entities, or "virtual processors." This is a compromise between kernel-level ("1:1") and user-level ("N:1") threading. In general, "M:N" threading systems are more complex to implement than either kernel or user threads, because changes to both kernel and user-space code are required. In the M:N implementation, the threading library is responsible for scheduling user threads on the available schedulable entities; this makes context switching of threads very fast, as it avoids system calls.
More details can be found :
It's not up to the C# itself, but rather the runtime - CLR.
.Net can be considered to support two modes:
Direct kernel mode threading is not allowed, because managed code does not have privileges to run in the kernel mode. It can only call Windows API, which in turn switch into the kernel mode.
If you use a Thread
, Task
, ThreadPool
- CLR uses hybrid model. A hybrid model is used because CLR creates managed object to represent that classes. Any managed code runs in the user-land. However, every thread that is not created as a fibber (see below), be it in a thread pool or not, has got underlying kernel data structures. Kernel data structures are used to hold the thread's kernel state - kernel thread id, create and exit times, process id, start thread address, security access token, dozen of timers, CPU register, kernel stack etc. All these need to be updated during a context switch, but we just take the hit of roughly 10-20 * 10^-6 sec it takes.
If you use a managed wrapper around Ums set of C++ calls (like CreateUmsThreadContext, UmsThreadYield and many others) - CLR attempts to use UMS mode. But this is only specific to the few threads you specifically and manually manipulate. Your application will still use the hybrid model, just a few manually picked threads (fibbers) will be manually yielded between each other in user mode. But even in this mode, at some point OS task scheduler will initiate a kernel thread switch, so you are not stuck executing UMS scheduled threads for ever.
For completeness,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With