The relationship between the kernel and the user thread

Is there a connection between the kernel and the user thread?

Some operating system textbooks say that " maps one (many) user thread to one (many) kernel thread." What does the card mean?

+44
operating-system kernel
Jul 24 '09 at 16:39
source share
5 answers

When they talk about a map, they mean that each kernel thread is assigned to a certain number of user-mode threads.

Kernel threads are used to provide privileged services to applications (such as system calls). They are also used by the kernel to track that everything is working on the system, how many resources are allocated for which process, and plan them.

If your applications make heavy use of system calls, there are more user threads per kernel thread and your applications will run slower. This is because the kernel thread will become a bottleneck because all system calls will go through it.

However, if your programs rarely use system calls (or other kernel services), you can assign a large number of user threads to the kernel thread without significantly reducing performance other than service ones.

You can increase the number of kernel threads, but this adds additional costs to the kernel as a whole, therefore, while individual threads will be more flexible with respect to system calls, the system as a whole will become slower.

This is why it is important to find a good balance between the number of kernel threads and the number of user threads in each kernel thread.

+40
Jul 24 '09 at 16:56
source share

http://www.informit.com/articles/printerfriendly.aspx?p=25075

Implementing streams in user space

There are two main ways to implement a stream package: in user space and in the kernel. The choice is moderately controversial, and a hybrid implementation is possible. Now we will describe these methods, as well as their advantages and disadvantages.

The first method is to put the stream package completely in user space. The kernel knows nothing about them. As for the kernel, it manages the usual single-threaded processes. The first and most obvious advantage is that a user-level thread package can be implemented in an operating system that does not support threads. All operating systems used for this category, and even some of them, still do.

All these implementations have the same general structure, which is illustrated in Fig. 2-8 (a). Threads run on top of a runtime system, which is a set of procedures that control threads. We have already seen four of them: thread_create, thread_exit, thread_wait and thread_yield, but usually there are more of them.

When threads are managed in user space, each process needs its own table of its own threads in order to track threads in this process. This table is similar to the kernel process table, except that it only tracks the properties of each thread, such as each thread's thread counter, stack pointer, registers, state, etc. The thread table is managed by the runtime system. When a thread moves to a ready state or is blocked, the information necessary to restart it is stored in the thread table in the same way that the kernel stores information about processes in the process table.

When a thread executes something that might lead to its local blocking, for example, expecting another thread to complete some work in the process, it calls the run-time system procedure. This procedure checks if the thread should be placed in a blocked state. If so, it stores the thread registers (that is, its own) in the thread table, looks at the table for the finished thread to start, and reloads the machine registers with the new values ​​stored in the thread. Once the stack pointer and program counter have been switched, the new thread comes to life again automatically. If the machine has instructions for storing all the registers and another for loading them, the entire thread switch can be executed in several instructions. Switching threads in this way is at least an order of magnitude faster than capturing the kernel, and is a good argument in favor of user-level thread packages.

However, there is one key difference from processes. When a thread is currently completed, for example, when it calls thread_yield, thread_yield code can store thread information in the thread table itself. Alternatively, it can then call the thread scheduler to select a different thread to start. The procedure for saving the state of the thread and the scheduler is only local procedures, so their use is much more efficient than calling the kernel. Among other problems, a trap is not required, there is no need to switch context, there is no need to clear the memory cache, etc. This makes thread planning very fast.

User level streams also have other advantages. They allow each process to have its own scheduling algorithm. For some applications, for example, those who have a garbage collector, there is no need to worry that a thread stopped at an inconvenient moment is a plus. They also scale better, since kernel threads invariably require some table space and stack space in the kernel, which can be a problem if there are a very large number of threads.

Despite its best performance, user-level threadstreams have some serious issues. The first of these is the problem of introducing lock system calls. Suppose a stream is read from the keyboard before all keys have been deleted. Preventing a thread actually makes the system call unacceptable, as it will stop all threads. One of the main goals of creating threads was primarily to allow each of them to use blocking calls, but to prevent one blocked thread from overlapping with the others. With system call blocking, it's hard to figure out how to achieve this goal.

All system calls can be changed to be non-blocking (for example, reading on the keyboard will simply return 0 bytes if the characters are no longer buffered), but requiring changes to the operating system are unattractive. In addition, one of the arguments for user-level threads was that they could work with existing operating systems. In addition, changing the semantics of reading will require changes in many user programs.

Another alternative is possible if it is possible to inform in advance whether the call will be blocked. On some versions of UNIX, there is a system call, select, exists, which allows the caller to determine whether the intended read will be blocked. When this call is present, the reading of the library procedure can be replaced by a new one, which first makes the select call and then only executes the read call if it is safe (i.e., it will not be blocked). If the read call is blocked, the call will not be completed. Instead, another thread executes. The next time the run-time system gains control, it can check again to make sure that reading is now safe. This approach requires rewriting parts of the system call library, inefficient and inefficient, but there is little choice. The code placed around the system call for verification is called a jacket or wrapper.

To some extent, similar to the problem of blocking system calls - the problem of page errors. We study them in chap. 4. At the moment, it is enough to say that computers can be configured in such a way that not all the program is in the main memory at once. If the program calls or proceeds to an instruction that is not in memory, a page error occurs and the operating system goes over and receives the missing command (and its neighbors) from the disk. This is called a page error. The process is blocked when the necessary instruction is found and read. If a thread causes a page error, the kernel, even without knowing the existence of threads, naturally blocks the entire process until the disk I / O is completed, even though other threads can be started.

Another problem with user-level stream packets is that if a thread starts, no other thread will ever work in this process unless the first thread voluntarily abandons the processor. Within one process, there are no clock interrupts, which makes it impossible to schedule processes in a cyclic way (in turn). If a thread does not enter the temporary system of its own free will, the scheduler will never get a chance.

One possible solution to the thread problem being executed forever is to force the runtime system to request a synchronization signal (interrupt) once per second to give it control, but it is also rude and random to program. Periodic clock interruptions at a higher frequency are not always possible, and even if they are, the total overhead can be significant. In addition, the thread may also need to interrupt the clock signal, which interferes with the use of the runtime system.

Another and probably the most destructive argument for user-level threads is that programmers usually want threads in applications where threads are often blocked, for example, on a multi-threaded web server. These threads constantly cause system calls. Once a trap has occurred with the kernel to make a system call, it is unlikely that more work on the kernel to switch threads if the old one is blocked, and the presence of this kernel eliminates the need to constantly select system calls that check if system read calls are safe. For applications that are essentially completely CPU-bound and rarely blocked, what's the point of having threads? No one would seriously suggest calculating the first n prime numbers or playing chess using streams, because nothing will work out doing it this way.

+18
Feb 20 '10 at 4:08
source share

User flows are managed in user space - this means scheduling, switching, etc. They do not come from the core.

Since, ultimately, the OS kernel is responsible for switching the context between the "execution units" - your user threads must be connected (i.e., "Display") with the planned kernel object - kernel thread 1 .

So, given N user threads, you can use N kernel threads (1: 1 map). This allows you to take advantage of hardware multi-processor kernel processing (running on multiple processors) and be a fairly simplified library - basically just putting aside most of the work on the kernel. This, however, makes your application portable between OSs, as you do not directly call kernel thread functions. I believe that POSIX Threads ( PThreads ) is the preferred * nix implementation, and that it follows a 1: 1 map (which makes it almost equivalent to a kernel thread). This, however, is not guaranteed, as it will be implementation dependent (the main reason for using PThreads will be portability between kernels).

Or you can use only 1 kernel thread. This would allow you to work in non-multi-tasking operating systems or be fully responsible for planning. Windows user mode planning is an example of this N: 1 card.

Or you can map an arbitrary number of kernel threads — a N: M map. Windows has Fibers that let you map N fibers to M kernel threads and plan them together. An example of this can also be a pool of threads - N work items for M threads.

1 : The process has at least 1 core thread, which is the actual unit of execution. In addition, the kernel thread must be contained in the process. The OS should schedule a thread to start, not a process.

+16
Jul 24 '09 at 17:32
source share
  • This is a question about implementing a thread library.
  • On Linux, a thread (or task) can be in user space or in kernel space. A process enters kernel space when it asks the kernel to do something using syscall (read, write, or ioctl).
  • There is also a so-called kernel thread that always runs in kernel space and does not represent any user process.
0
Dec 23 '13 at 5:51 on
source share

According to Wikipedia and Oracle , user-level threads are actually in a layer installed on kernel threads; not that kernel threads execute along with user-level threads, but generally speaking, the only entities that are actually executed by the processor / OS are kernel threads.

For example, suppose we have a program with 2 user-level threads that are mapped (i.e. assigned) by the same kernel thread. Sometimes the kernel thread starts the first user-level thread (and they say that this kernel thread is currently mapped to the first user-level thread), and in some cases the kernel thread starts the second user-level thread. Therefore, we say that we have two user-level threads mapped to the same kernel thread.

As an explanation :

The kernel of the OS is called kernel , so threads at the kernel level (that is, threads that the kernel knows about and manages) are called kernel threads, calls to the OS kernel for services can be called kernel calls and .... The only definite relationship between the kernel is that they are strongly connected with the OS kernel, nothing more.

0
Mar 06 '14 at 10:23
source share



All Articles