Linux User Space Threads, Kernel Threads, Lightweight Processes

Linux user space threads, kernel threads , lightweight processes

In pthreads on Linux, the thread scheduling is handled by the kernel.

In Linux, a thread or process is created with the clone() system call (fork() is a special case of clone). Depending on the options passed to clone, the newly created process will be lighter weight or a heavier weight (i.e. having a separate memory space and a separate set of file descriptors etc.). pthread_create() uses clone() with a minimum amount of separation.

It is also possible to not make use of native threads at all, and instead use a fully userspace implementation of threading, using setjmp() and longjmp(). This could be used to implement some interpreted language, for example. However, I am not aware of a concrete example of a program or library that actually does implement its own userspace scheduler.

One more thing: a "kernel thread" is generally used to designate a thread that runs in kernel space, i.e. that is part of the kernel itself. In ps such threads are recognisable because they are surrounded with square brackets, like [kthreadd].

How to create light weight kernel thread?

Kernel threads are always listed in the process table, but this is merely a cosmetical issue. They share the same address space and *-tables, so in this sense they are quite lightweight anyway (i.e. a context-switch isn't very expensive).

If your 2*16 kernel-threads mainly do the same thing, it might be worthy evaluating if the functionality can be moved into a seperate kernel-module, which exposes an API to be used by all 16 kernel-modules and doing the work in only 1 or 2 threads.

What is the difference between lightweight process and thread?

From MSDN, Threads and Processes:

Processes exist in the operating system and correspond to what users
see as programs or applications. A thread, on the other hand, exists
within a process. For this reason, threads are sometimes referred to
as light-weight processes.
Each process consists of one or more
threads.

examples of user-space threading and kernel-space threading

I am using the terminology set out in this Wikipedia page

  • https://en.wikipedia.org/wiki/Thread_(computing).

(I'll leave it to you to figure out if that terminology matches your Arabic course curriculum.)



Q1: Provide examples of user-space-threaded systems and kernel-space-threaded systems.

Modern Linux systems support kernel threads.

Old Linux and old Unix systems didn't support kernel threads, so if you needed threading you have to implemented it entirely in user space. The old Java "green threads" model was an example of threads implemented entirely in user space.

Q2: Is Native POSIX Thread Library is considered part of user-space or kernel-space.

The Native POSIX Thread Library (NPTL) is actually an API. It could be implemented in many ways.

Typical implementations (e.g. current Linux ones) use kernel threads; i.e. there is a 1:1 mapping between a "user-space" thread abstraction, and "kernel-space" threads or Light Weight Processes managed by the kernel.

Q3: Is Java threading is done in user-space.

Not in modern Java implementations. The first JVM implementations used user-space threads (aka green threads).


Note that there is debate over the true meaning of "user-space" and "kernel" thread, and how pthreads and NPTL fits into the taxonomy; see Is Pthread library actually a user thread solution?.

How user level thread talk with kernel level thread

Kernel threads are like a specialized task responsible for doing a specific operation (not meant to last long). They are not threads waiting for incoming request from user-land threads. Moreover, a system call does not systematically create a kernel thread (see this post for more information and this one for some context about system calls): a kernel thread is started when a background task is required like for dealing with IO requests for example (this post shows a good practical case though the description is a bit deep). Basic system calls just runs in the same user-thread but with higher privileges. Note the kernel functions use a dedicated kernel stack: each user-level thread has 2 stacks on Linux: one for user-land functions and one for kernel-land functions (for sake of security).

As a result, in practice, I think all answers are wrong in usual cases (ie. assuming the target operation do not require to create a kernel thread). If the target system calls done actually require to create kernel threads, then b) is the correct answer. Indeed, kernel threads are like a one-shot specialized task as previously stated. Creating/Destroying new kernel-threads is not much expensive since it is just basically a relatively lightweight task_struct data structure internally.

How does the kernel separate threads from processes

Unlike Windows, Linux does not have an implementation of "threads" in the kernel. The kernel gives us what are sometimes called "lightweight processes", which are a generalization of the concepts of "processes" and "threads", and can be used to implement either.

It may be confusing when you read kernel code and see things like thread_struct on the one hand, and pid (process ID) on the other. In reality, both are one and the same. Don't be confused by the terminology.

Each lightweight process has a completely different thread_info and task_struct (with embedded thread_struct). You seem to think that the task_struct of one lightweight process should have pointers to the task_structs of other (userspace) "threads" in the same (userspace) "process". This is not the case. Inside the kernel, each "thread" is a separate process, and the scheduler deals with each one separately.

Linux has a system call called clone which is used to create new lightweight processes. When you call clone, you must provide various flags which indicate what will be shared between the new process and the existing process. They can share their address space, or they can each have a different address space. They can share their open files, or they can each have their own list of open files. They can share their signal handlers, or they can each have their own signal handlers. They can be in the same "thread group", or they can be in different thread groups. And so on...

Although "threads" and "processes" are the same thing in Linux, you can implement what we normally think of as "processes" by using clone to create processes which do not share their address space, open files, signal handlers, etc.

You can also implement what we normally think of as "threads" by using clone to create processes which DO share their address space, open files, signal handlers, etc.

If you look at the definition of task_struct, you will find that it has pointers to other structs such as mm_struct (address space), files_struct (open files), sighand_struct (signal handlers), and so on. When you clone a new "process", all of these structs will be copied. When you clone a new "thread", these structs will be shared between the new and old task_structs -- they will both point to the same mm_struct, the same files_struct, and so on. Either way, you are just providing different flags to clone to tell it what to copy, and what to share.

I just mentioned "thread groups" above, so you might wonder about that. In short, each "thread" in a "process" has its own PID, but they all share the same TGID (thread group ID). The TGIDs are all equal to the PID of the first program thread. Userspace "PIDs", like those shown in ps, or in /proc, are actually "TGIDs" in the kernel. Naturally, clone has a flag to determine whether a new lightweight process will have a new TGID (thus putting it in a new "thread group") or not.

UNIX processes also have "parents" and "children". There are pointers in a Linux task_struct which implement the parent-child relationships. And, as you might have guessed, clone has a flag to determine what the parent of a new lightweight process will be. It can either be the process which called clone, OR the parent of the process which called clone. Can you figure out which is used when creating a "process", and which is used when creating a "thread"?

Look at the manpage for clone; it will be very educational. Also try strace on a program which uses pthreads to see clone in use.

(A lot of this was written from memory; others should feel free to edit in corrections as necessary)



Related Topics



Leave a reply



Submit