Difference between user-level and kernel-supported threads? Difference between user-level and kernel-supported threads? multithreading multithreading

Difference between user-level and kernel-supported threads?


Edit: The question was a little confusing, so I'm answering it two different ways.

OS-level threads vs Green Threads

For clarity, I usually say "OS-level threads" or "native threads" instead of "Kernel-level threads" (which I confused with "kernel threads" in my original answer below.) OS-level threads are created and managed by the OS. Most languages have support for them. (C, recent Java, etc) They are extremely hard to use because you are 100% responsible for preventing problems. In some languages, even the native data structures (such as Hashes or Dictionaries) will break without extra locking code.

The opposite of an OS-thread is a green thread that is managed by your language. These threads are given various names depending on the language (coroutines in C, goroutines in Go, fibers in Ruby, etc). These threads only exist inside your language and not in your OS. Because the language chooses context switches (i.e. at the end of a statement), it prevents TONS of subtle race conditions (such as seeing a partially-copied structure, or needing to lock most data structures). The programmer sees "blocking" calls (i.e. data = file.read() ), but the language translates it into async calls to the OS. The language then allows other green threads to run while waiting for the result.

Green threads are much simpler for the programmer, but their performance varies: If you have a LOT of threads, green threads can be better for both CPU and RAM. On the other hand, most green thread languages can't take advantage of multiple cores. (You can't even buy a single-core computer or phone anymore!). And a bad library can halt the entire language by doing a blocking OS call.

The best of both worlds is to have one OS thread per CPU, and many green threads that are magically moved around onto OS threads. Languages like Go and Erlang can do this.

system calls and other uses not available to user-level threads

This is only half true. Yes, you can easily cause problems if you call the OS yourself (i.e. do something that's blocking.) But the language usually has replacements, so you don't even notice. These replacements do call the kernel, just slightly differently than you think.


Kernel threads vs User Threads

Edit: This is my original answer, but it is about User space threads vs Kernel-only threads, which (in hindsight) probably wasn't the question.

User threads and Kernel threads are exactly the same. (You can see by looking in /proc/ and see that the kernel threads are there too.)

A User thread is one that executes user-space code. But it can call into kernel space at any time. It's still considered a "User" thread, even though it's executing kernel code at elevated security levels.

A Kernel thread is one that only runs kernel code and isn't associated with a user-space process. These are like "UNIX daemons", except they are kernel-only daemons. So you could say that the kernel is a multi-threaded program. For example, there is a kernel thread for swap. This forces all swap issues to get "serialized" into a single stream.

If a user thread needs something, it will call into the kernel, which marks that thread as sleeping. Later, the swap thread finds the data, so it marks the user thread as runnable. Later still, the "user thread" returns from the kernel back to userland as if nothing happened.

In fact, all threads start off in kernel space, because the clone() operation happens in kernel space. (And there's lots of kernel accounting to do before you can 'return' to a new process in user space.)


Before we go into comparison, let us first understand what a thread is. Threads are lightweight processes within the domain of independent processes. They are required because processes are heavy, consume a lot of resources and more importantly,

two separate processes cannot share a memory space.

Let's say you open a text editor. It's an independent process executing in the memory with a separate addressable location. You'll need many resources within this process, such as insert graphics, spell-checks etc. It's not feasible to create separate processes for each of these functionalities and maintain them independently in memory. To avoid this,

multiple threads can be created within a single process, which can share a common memory space, existing independently within a process.

Now, coming back to your questions, one at a time.

I'm not really to sure about the differences between user-level and kernel-level threads.

Threads are broadly classified as user level threads and kernel level threads based on their domain of execution. There are also cases when one or many user thread maps to one or many kernel threads.

- User Level Threads

User level threads are mostly at the application level where an application creates these threads to sustain its execution in the main memory. Unless required, these thread work in isolation with kernel threads.

These are easier to create since they do not have to refer many registers and context switching is much faster than a kernel level thread.

User level thread, mostly can cause changes at the application level and the kernel level thread continues to execute at its own pace.

- Kernel Level Threads

These threads are mostly independent of the ongoing processes and are executed by the operating system.

These threads are required by the Operating System for tasks like memory management, process management etc.

Since these threads maintain, execute and report the processes required by the operating system; kernel level threads are more expensive to create and manage and context switching of these threads are slow.

Most of the kernel level threads can not be preempted by the user level threads.

MS DOS written for Intel 8088 didn't have dual mode of operation. Thus, a user level process had the ability to corrupt the entire operating system.

- User Level Threads mapped over Kernel Threads

This is perhaps the most interesting part. Many user level threads map over to kernel level thread, which in-turn communicate with the kernel.

Some of the prominent mappings are:

One to One

When one user level thread maps to only one kernel thread.

advantages: each user thread maps to one kernel thread. Even if one of the user thread issues a blocking system call, the other processes remain unaffected.

disadvantages: every user thread requires one kernel thread to interact and kernel threads are expensive to create and manage.

Many to One

When many user threads map to one kernel thread.

advantages: multiple kernel threads are not required since similar user threads can be mapped to one kernel thread.

disadvantage: even if one of the user thread issues a blocking system call, all the other user threads mapped to that kernel thread are blocked.

Also, a good level of concurrency cannot be achieved since the kernel will process only one kernel thread at a time.

Many to Many

When many user threads map to equal or lesser number of kernel threads. The programmer decides how many user threads will map to how many kernel threads. Some of the user threads might map to just one kernel thread.

advantages: a great level of concurrency is achieved. Programmer can decide some potentially dangerous threads which might issue a blocking system call and place them with the one-to-one mapping.

disadvantage: the number of kernel threads, if not decided cautiously can slow down the system.

The other part of your question:

kernel-supported threads have access to the kernel for system calls and other uses not available to user-level threads.

So, are user-level threads simply threads created by the programmer when then utilise kernel-supported threads to perform operations that couldn't be normally performed due to its state?

Partially correct. Almost all the kernel thread have access to system calls and other critical interrupts since kernel threads are responsible for executing the processes of the OS. User thread will not have access to some of these critical features. e.g. a text editor can never shoot a thread which has the ability to change the physical address of the process. But if needed, a user thread can map to kernel thread and issue some of the system calls which it couldn't do as an independent entity. The kernel thread would then map this system call to the kernel and would execute actions, if deemed fit.


User Threads

  1. The library provides support for thread creation, scheduling and management with no support from the kernel.
  2. The kernel unaware of user-level threads creation and scheduling are done in user space without kernel intervention.
  3. User-level threads are generally fast to create and manage they have drawbacks however.
  4. If the kernel is single-threaded, then any user-level thread performing a blocking system call will cause the entire process to block, even if other threads are available to run within the application.
  5. User-thread libraries include POSIX Pthreads, Mach C-threads,and Solaris 2 UI-threads.

Kernel threads

  1. The kernel performs thread creation, scheduling, and management in kernel space.
  2. kernel threads are generally slower to create and manage than are user threads.
  3. the kernel is managing the threads, if a thread performs a blocking system call.
  4. A multiprocessor environment, the kernel can schedule threads on different processors.5.including Windows NT, Windows 2000, Solaris 2, BeOS, and Tru64 UNIX (formerlyDigital UN1X)-support kernel threads.