Threads: Why must all user threads be mapped to a kernel thread? - multithreading

So two questions here really. First, (and yes, I have searched this already, but wanted clarification), what is the difference between a user thread and a kernel thread? Is it simply that one is generated by a user program and the other by an OS, with the latter having access to privileged instructions? Are they conceptually the same or are there actual differences in the threads themselves?
Second, and the real problem of my question is: the book I am using says that "a relationship must exist between user threads and kernel threads," going on to list the different models of such a relationship. But the book fails to clearly explain why a user thread must always be mapped to a specific kernel thread. Why is this?

A kernel thread is a thread object maintained by the operating system. It is an actual thread that is capable of being scheduled and executed by the processor. Typically, kernel threads are heavyweight objects with permissions settings, priorities, etc. The kernel thread scheduler is in charge of scheduling kernel threads.
User programs can make their own thread schedulers too. They can make their own "threads" and simulate context-switches to switch between them. However, these threads aren't kernel threads. Each user thread can't actually run on its own, and the only way for a user thread to run is if a kernel thread is actually told to execute the code contained in a user thread. That said, user threads have major advantages over kernel threads. They can be a lot more lightweight, since they don't necessarily need to have their own priorities, can be managed by a single process (which might have better info about what threads need to run when), and don't create lots of kernel objects for purposes of security and locking.
The reason that user threads have to be associated with kernel threads is that by itself a user thread is just a bunch of data in a user program. Kernel threads are the real threads in the system, so for a user thread to make progress the user program has to have its scheduler take a user thread and then run it on a kernel thread. The mapping between user threads and kernel threads doesn't have to be one-to-one (1 : 1); you can have multiple user threads share the same kernel thread (only one of those user threads runs at a time), and you can have a single user thread which is rotated across different kernel threads in a 1 : n mapping.

I think a real world example will clear the confusion, so let’s see how things are done in Linux.
First of all Linux doesn’t differentiate between process and thread, entity that can be scheduled is called task in Linux and represented by task_struct. So whenever you execute a fork() system call, a new task_struct is created which holds data (or pointer) associated with new task.
So in Linux world a kernel thread means a task_struct object.
Because scheduler only knows about these entities which can be assigned to different CPU’s (logical or physical). In other words if you want Linux scheduler to schedule your process you must create a task_struct.
User thread is something that is supported and managed outside of kernel by some execution environment (EE from now on) such as JVM. These EE’s will provide you with some functions to create new threads.
But why a user thread must always be mapped to a specific kernel thread.
Let’s say you created some threads using your EE. eventually they must be executed by the CPU and from above explanation we know that the thread must have a task_struct in order to be assigned to some CPU. That is why the mapping must exist. It’s the duty of your EE to create task_structs.
If your EE uses many to one model then it will create only one task_struct for all the threads and it will schedule all these threads onto that task_struct. Think of it as there is one CPU (task_struct) and many processes (threads created in EE), your operating system (the EE) will multiplex these processes on that single CPU.
If it uses one to one model than there will be one task_struct for every thread created in EE. So when you create a new thread in your EE, corresponding task_struct gets created in the kernel.
Windows does things differentlly ( process and thread is different ) but general idea stays the same that is kernel thread is the entity that CPU scheduler considers for assignment hence user threads must be mapped to corresponding kernel threads (if you want CPU to execute them).

Related

If you have One-to-One-Mapping of Kernel- and User-Threads, why isn't process be blocked, if it makes a system-call?

I often read that when you have many-to-one-mapping, a sys-call would block the whole process, but a one-to-one would'nt. But why? The Thread that makes the sys-call is blocked anyway and can't make a switch-command to the other user-thread.
The kernel schedules the threads not the processes globally.
In a very general case when a process is made of just its main thread, we use a kind of shortcut in the manner of speaking and say that the kernel schedules those processes, but it is just a (very common) corner case.
Each thread can have its own priority, its own affinity to some CPUs...
But by default these properties are inherited from the main thread in the process it belongs to, and if we don't change them explicitly, we can have the illusion that all these threads inside a single process form one single entity from the scheduler point of view; but it is not the case.
When one thread is blocked on a system call for example, this does not prevent the other threads from being run.
The blocked thread does not decide of anything concerning the next thread to be run (except if we explicitly build a dedicated applicative synchronisation mechanism with cond-vars...).
The switch to another thread, in the same or another process, is entirely decided by the OS scheduler.
Another confusing situation for example is when a segmentation fault occurs in a thread.
Since the address space is shared between all the threads inside a single process, this is the process as a whole that must be terminated.
Then all its threads disappear at once, which gives again the illusion that all these threads form one single entity from the scheduler point of view; but it is more related to address space management than scheduling.
note: there may exist some user-space implementations of threads in which the OS scheduler have no way to consider these threads as distinct (it sees only the main thread of the process).
Depending on the internal details of such user-space implementations, a blocking system call could lead to blocking the entire process or not.
Nowadays, it is much more common to rely on the native threads provided by the kernel.
I think there's one very specific thing that you're missing.
When you have a one-to-one mapping of user threads to kernel threads, that means that each user thread has its own kernel thread. There's no "switch-command to the other user thread" because the other user thread is another kernel thread, and it's the kernel's job to switch between kernel threads. On modern operating systems, the kernel can easily switch kernel threads when a thread is blocked in a system call.
When you have a many-to-one mapping of user threads, that means a single kernel thread is expected to run code for more than one user thread. Here, the user code has to do something to cause that same kernel thread to execute code for another user thread. It can't do that if it's blocked in a system call.

one-to-one multi-threading model

In silberschatz "Operating System Concepts" book, section 4.3.2 says that
one-to-one model provides more concurrency than the many-to-one model
by allowing another thread to run when a thread makes a blocking
system call. It also allows multiple threads to run in parallel on
multiprocessors.
I have two questions here:
How can one thread be blocked and other mapped on kernel thread?
Dont we know that if one thread is blocked, entire process of that
user-level thread is blocked?
The OS considers user-level threads
as one thread only. It cant be assigned to multiple
processors/cores. Isn't the below given line contradicting that
idea?
It also allows multiple threads to run in parallel on
multiprocessors
Your understanding of user level threads and kernel level threads is not correct, in particular you need to understand how user level threads are mapped to kernel level threads. So first lets define some terms
Kernel thread
A thread (schedulable task) that is created and managed by the kernel. Every kernel level thread is represented by some data structure which contains information related to the thread. In the case of Linux it is task_struct. Kernel threads are the only threads that are considered by the CPU scheduler for scheduling.
Note : Kernel thread is a bit of misnomer as Linux kernel doesn't distinguish between a thread and a process, schedulable task would better describe this entity.
User thread
A thread that is created and managed by some library such as JVM above kernel level. The library that creates these threads is responsible for their management that is which thread runs and when.
User level to kernel level mapping
Now you can create as many user level threads as you want but to execute them you need to create some kernel level thread (task_struct). This creation of kernel level threads can be done in many ways
One to one model
In this case whenever you create a user level thread your library asks the kernel to create a new kernel level thread. In the case of Linux your library will use clone system call to create a kernel level thread.
Many to one model
In this case your library creates only one kernel level thread (task_struct). No matter how many user level threads you create they all share the same kernel level thread, much like the processes running on a single core CPU. The point to understand is that your library here acts much like the CPU scheduler, it schedules many user level threads on single kernel level thread.
Now to your question
The OS considers user-level threads as one thread only. It can’t be
assigned to multiple processors/cores. Isn't the below given line
contradicting that idea?
If you were using many to one model, in that case you will have only one kernel level thread for all of your user level threads and hence they cannot run on different CPU’s.
But if you are using a one to one model then each of your user level threads has a corresponding kernel level thread that can be scheduled individually and hence user level threads can run on different CPU’s given that you have more than one CPU.
You are suffering from a confusing book.
There are real threads (aka kernel threads, 1 to 1 model) and there are simulated threads (aka user threads, many to 1 model).
Some books make this more confusing by throwing a hypothetical many to many model.
User threads are obsolete. Any operating system book worth reading these days would treat them that way and describe them in historical terms.
How can one thread be blocked and other mapped on kernel thread? Dont we know that if one thread is blocked, entire process of that user-level thread is blocked?
You either have user threads or kernel thread. An application that did both would be royally screwed up.
The OS considers user-level threads as one thread only. It cant be assigned to multiple processors/cores. Isn't the below given line contradicting that idea?
In ye olde days a process was considered to be an execution stream and an address space. There were no threads. When threads became necessary (largely due to the need for Ada support), they were simulated using timers. The behavior of threads varied by operating system.
In Eunuchs variants, blocking calls block the process entirely. Thus in simulated (user) threads a blocking call in one thread would block all threads. This is not true on all operating systems.
Now, a process is one or more execution streams and an address space. That is what you ought be learning; not a bunch of technobabble.
A book that talks about threads in terms of 1-to-1 or many-to-1 models is only fit to line cat boxes.

Are there any entries for User Level Threads in the Thread Table maintained by the OS?

I was studying about ULTs and KLTs and had this doubt in mind . If the OS cannot differentiate between a ULT and a process then does it have any ULT entries in its Thread Table ?
If the OS cannot differentiate between a ULT and a process then does
it have any ULT entries in its Thread Table ?
No -- as far as the OS is concerned, User Level Threads do not exist. Rather, there is just a single thread/process, which is doing "interesting things" with calls to setjmp() and longjmp().
No.
Operating system (kernel) only knows about kernel level threads and have no knowledge of user level threads. User level threads are managed by user library that provides thread functionality.
For example Linux doesn’t differentiate between a thread and process. The entity that can be scheduled is represented by task_struct data structure.
So when your library wants to create some threads it asks kernel to create (using clone ()) corresponding task_structs. Your library may ask for only one task_struct in which case all your user level threads are multiplexed on the same task_struct or it may ask for one task_struct for each user level thread in which case every user level thread can be considered by kernel for scheduling because every thread has a task_struct.
So in summary we can say that
Kernel only knows about kernel level threads. User level threads are created and managed by the respective library.

Differences between Multi-threading Models

Many-to-One Model
One-to-One Model
Many-to-Many Model
Advantages and disadvantages of each model ?
Can you give an example ?
EDIT:
One thing is confusing me with the Many-to-One Model
I'm quoting the book:
"Thread management is done by the thread library in user space, so it
is efficient; but the entire process will block if a thread makes a
blocking system call. Also, because only one thread can access the
kernel at a time, multiple threads are unable to run in parallel on
multiprocessors"
Does it mean all processes in kernel will be blocked, due to the fact that the swapping is done by the application, not by OS scheduler.
(since in this model we manage threads in user-mode) ?
Or, only the threads belonging to the same process of the thread that made the blocking system call will be blocked ?
Thanks in advance!
We have to assign user level threads to kernel level threads, based on the this the mapping can be:
One to one (One user thread mapped to one kernel level thread)
Many to one(Many User level threads mapped to one kernel level thread)
Many to many(Many User level threads mapped to many kernel level threads)
Here the number of kernel level threads are generally set to lesser than number of user level thread, since management of kernel level threads is much more expensive since it involves kernel intervention in their(kernel level thread's) management.
Because of this reason only the fourth mapping of "one to many"(one user level thread to multiple kernel level threads) to one does not make sense.
"Thread management is done by the thread library in user space, so it is efficient; but the entire process will block if a thread makes a blocking system call. Also, because only one thread can access the kernel at a time, multiple threads are unable to run in parallel on multiprocessors"
this example may help to understand this line:
Does it mean all processes in kernel will be blocked, due to the fact that the swapping is done by the application, not by OS scheduler. (since in this model we manage threads in user-mode) ? Or, only the threads belonging to the same process of the thread that made the blocking system call will be blocked ?
One process's threads are independent of other process's threads.So only the threads belonging to the same process of the thread that made the blocking system call will be blocked.
I hope this does make sense to you...
I can see your problem. You have a horrible book.
You're asking about a couple of related issues. First of all, there are two general ways to implement threads.
1) Threads are implemented in a library using timers. In systems that schedule processes for execution this is the only way to do thread. This was ONLY way to do threads in the olde days. This system is usually called "user threads." User threads are multiplexed within a process. The process does the scheduling of its own threads.
The mythical advantage of "user threads" over "kernel threads" (below) is that they are more efficient. This is what your quoted passage is referring to. The statement "the entire process will block if a thread makes a blocking system call" is only true on some [unix] systems.
2) Threads are implemented in the operating system. A process consists of an address space and one or more threads. The operating system kernel schedules THREADS for execution rather than PROCESSES. These are kernel thread.
Note that even if the system supports kernel threads, it is possible for a process to use user threads. The two are not mutually exclusive. However, a system that does not natively support kernel threads can only use user thread.
That's the simple way to explain the different threading models.
-=-=-=-=-=-=-=-=-=-=-=-
The one-to-one, many-to-one, and many-to-many models are a needless confusion for students. Now we have to get into overlapping terminology.
Let's change the terminology around. For #1, instead of calling the schedulable unit of execution a "process" we call it a "kernel thread." There can only be one kernel thread per process in this model. Then the threads in the process are are "user threads." Any number of user threads execute within/are mapped to a kernel thread. This is then the many-to-one model. User threads = many-to-one.
If we have the operating system create the thread (a kernel thread), let's theoretically call what is being executed a "user thread." Each user thread maps to/executed in one and only one kernel thread. This is then the one-to-one model.
The many-to-one model is the same as what is normally called "user threading model."
The terminology is starting to get nonsensical because there is only one thread but we are calling it a user thread mapped to a kernel thread.
The one-to-one model is what is normally called the kernel threading model.
Lastly, we get to the many-to-many model. It is theoretical BS. In theory, there could be many user threads mapped to many kernel threads. In other words, a single user thread could execute within different kernel threads. I have never heard of system implementing threads this way and I cannot imagine any practicable advantage of such a system.
-=-=-=-=-=-=-=-=-=-=-=-=-
As to your last question, in some operating systems, blocking system calls block also block the timers used to implement user threads (a/k/a many-to-one). If one thread make blocking call, it blocks all the other threads in the PROCESS from executing until the blocking call completes.
This blocking does not occur in all systems (something an OS textbook should point out).

execution of user-level-threads on Kernel threads - many to one [duplicate]

So two questions here really. First, (and yes, I have searched this already, but wanted clarification), what is the difference between a user thread and a kernel thread? Is it simply that one is generated by a user program and the other by an OS, with the latter having access to privileged instructions? Are they conceptually the same or are there actual differences in the threads themselves?
Second, and the real problem of my question is: the book I am using says that "a relationship must exist between user threads and kernel threads," going on to list the different models of such a relationship. But the book fails to clearly explain why a user thread must always be mapped to a specific kernel thread. Why is this?
A kernel thread is a thread object maintained by the operating system. It is an actual thread that is capable of being scheduled and executed by the processor. Typically, kernel threads are heavyweight objects with permissions settings, priorities, etc. The kernel thread scheduler is in charge of scheduling kernel threads.
User programs can make their own thread schedulers too. They can make their own "threads" and simulate context-switches to switch between them. However, these threads aren't kernel threads. Each user thread can't actually run on its own, and the only way for a user thread to run is if a kernel thread is actually told to execute the code contained in a user thread. That said, user threads have major advantages over kernel threads. They can be a lot more lightweight, since they don't necessarily need to have their own priorities, can be managed by a single process (which might have better info about what threads need to run when), and don't create lots of kernel objects for purposes of security and locking.
The reason that user threads have to be associated with kernel threads is that by itself a user thread is just a bunch of data in a user program. Kernel threads are the real threads in the system, so for a user thread to make progress the user program has to have its scheduler take a user thread and then run it on a kernel thread. The mapping between user threads and kernel threads doesn't have to be one-to-one (1 : 1); you can have multiple user threads share the same kernel thread (only one of those user threads runs at a time), and you can have a single user thread which is rotated across different kernel threads in a 1 : n mapping.
I think a real world example will clear the confusion, so let’s see how things are done in Linux.
First of all Linux doesn’t differentiate between process and thread, entity that can be scheduled is called task in Linux and represented by task_struct. So whenever you execute a fork() system call, a new task_struct is created which holds data (or pointer) associated with new task.
So in Linux world a kernel thread means a task_struct object.
Because scheduler only knows about these entities which can be assigned to different CPU’s (logical or physical). In other words if you want Linux scheduler to schedule your process you must create a task_struct.
User thread is something that is supported and managed outside of kernel by some execution environment (EE from now on) such as JVM. These EE’s will provide you with some functions to create new threads.
But why a user thread must always be mapped to a specific kernel thread.
Let’s say you created some threads using your EE. eventually they must be executed by the CPU and from above explanation we know that the thread must have a task_struct in order to be assigned to some CPU. That is why the mapping must exist. It’s the duty of your EE to create task_structs.
If your EE uses many to one model then it will create only one task_struct for all the threads and it will schedule all these threads onto that task_struct. Think of it as there is one CPU (task_struct) and many processes (threads created in EE), your operating system (the EE) will multiplex these processes on that single CPU.
If it uses one to one model than there will be one task_struct for every thread created in EE. So when you create a new thread in your EE, corresponding task_struct gets created in the kernel.
Windows does things differentlly ( process and thread is different ) but general idea stays the same that is kernel thread is the entity that CPU scheduler considers for assignment hence user threads must be mapped to corresponding kernel threads (if you want CPU to execute them).

Resources