2

I know there are three thread mapping model in operating system.

  1. One to One
  2. Many to One
  3. Many to Many

In this question I assume we use One to One model.

Let's say, right now I restart my computer, and there are 10 kernel-level threads already running.

After a while, I decide to run a python program which will launch one process with four threads. Three of the threads have to run a function that do a system call.

Here is a question, what is the correct scenario when I run the python program.

a) When a python program start, the kernel will launch another 4 threads in kernel space immediately (so there are 14 threads in kernel space now). When those 3 threads in user level initiate a system call, kernel will map those user-level threads to 3 of 4 kernel-level threads that kernel created when python program start, which also means we will waste 1 kernel-level thread.

b) When a python program start, the kernel will not launch another 4 threads in kernel space immediately. Instead, kernel will create new kernel-level threads whenever those 3 user-level thread initiate a system call and ready to talk with kernel. In this case kernel will just create 3 threads exactly, which also means we will not waste any kernel-level threads.

c) Very similar to second scenario, but in this case when those 3 user-level threads ready to run system call and talk with kernel, what kernel will do is make 3 of kernel-level threads that already created stop doing their current job, and then ask them to do the job that python program ask kernel do.

Which means the scheduler will pick up 3 random kernel-level threads to stop what they're doing, and then store those tasks information to somewhere. After that, scheduler will ask those 3 kernel-level thread to finish the python program job first. In this case we always have only 10 threads in kernel-level.

Any reply and suggested material to study is appreciated!

Peter
  • 61
  • 5

2 Answers2

3

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.

Jérôme Richard
  • 41,678
  • 6
  • 29
  • 59
  • Hey @Jérôme Richard, thanks for your reply. I have a following questions. I found this helpful link: http://www.it.uu.se/education/course/homepage/os/vt18/module-4/implementing-threads/#scheduler-activations In scheduler activation section part of the link, it said "The kernel provides the application with a set of kernel threads (virtual processors)". Is that what exactly scenario (b) doing? – Peter Sep 11 '22 at 07:46
  • One more question. Does it means we actually don't need to map user-level thread to kernel-level thread in usual case. Because we can simply provide higher privilege to user-level thread, and then that user-level thread will have a short time to be running in kernel space? – Peter Sep 11 '22 at 08:13
  • The provided course is a bit academic and does not really applies to Linux. For example, the course starts taking about the PCB but when searching about this in the Linux code and past answers, I did not found anything like that except the `task_struct` data structure (see [this](https://stackoverflow.com/questions/73514070)). As for the mapping, all mainstream OS use a 1-1 mapping (see [here](https://stackoverflow.com/questions/14792428) and [there](https://en.wikipedia.org/wiki/Thread_(computing))). In fact, it is not even a 1-1 but either 1-1 or 1-0 in practice. – Jérôme Richard Sep 11 '22 at 09:19
  • So such course (and books) are a pretty outdated or simply a bit too much academic. I also find talking about green threads (sometime called "user-level threads") and kernel threads in the same page is very confusing for students as this is [two completely different notions](https://cs.stackexchange.com/questions/74388) (I personally use "green thread" for user-level lightweight thread scheduling and "user-level thread" or "user thread" as native threads in user-land (it is OK to use "user-level threads" when this is not ambiguous: e.g. for people not talking about the kernel). – Jérôme Richard Sep 11 '22 at 09:24
  • Since Linux use a kind of 1-1/1-0 mapping, there is no such thing as "scheduler activation" system or "virtual processors" (not in this context at least): this is for "many-to-many model and the two-level model" as stated correctly in the course. To me, b) use a 1-1 mapping so "scheduler activation" does not applies. – Jérôme Richard Sep 11 '22 at 09:31
  • As for the mapping, yes, but please keep in mind that that this is not *not always* the case: it depends of the target system call. Indeed, Linux starts a kernel thread only when it is useful and this is rarely the case for regular system calls (eg. handle state probing, memory allocation, etc.). – Jérôme Richard Sep 11 '22 at 09:39
  • 1
    Feel free to accept the answer it is clear to you ;) . – Jérôme Richard Sep 11 '22 at 09:40
  • Very good answer. Lots of people have this misconception. Overall, the concept of "many-to-one", "one-to-one", etc, doesn't make sense in practice. It is actually mixing people up when they are thaught about OS kernels. – user123 Sep 11 '22 at 15:49
  • @Jérôme Richard, actually there is a pcb filed in struct thread_info, https://elixir.bootlin.com/linux/latest/source/arch/alpha/include/asm/thread_info.h#L15 – Peter Sep 11 '22 at 19:36
  • 1
    @Peter It clearly does not looks like a Process Control Block (this is what I mean by PCB, as in system books). The comment indicate "palcode state", the structure content seems unrelated, and it appears to be only present on the Alpha architecture which is AFAIK obsolete since at least 15 years (the last processor has been released in 2004 according to Wikipedia -- ie. 18 years ago). – Jérôme Richard Sep 11 '22 at 22:46
  • 1
    Oops, you are correct. It seems like the member of that pcb struct is not the PCB we are saying. Thanks! – Peter Sep 12 '22 at 02:45
0

To answer this question directly. You have mixed kernel threads and threading. They are not completely different concepts, but a little different at the OS level. Also, kernel threads may last indefinitely in many cases.

There are at least three types of data,

  1. thread_info - specific schedulable entity; always exists.
  2. task_struct - files open and other specific (not for kernel thread)
  3. A memory management context (usually, but not always).

For kernel threads, there is no memory management nor user space allocations. Kernel threads do have a separate stack in kernel space. Only kernel code may run in the context of the kernel stack, for example on behalf of user space via a syscall. It can also be borrowed during an interrupt; which may cause a context switch.

The initial 10 kernel threads are just a number to add to the total.

b) When a python program start, the kernel will not launch another 4 threads in kernel space immediately. Instead, kernel will create new kernel-level threads whenever those 3 user-level thread initiate a system call and ready to talk with kernel. In this case kernel will just create 3 threads exactly, which also means we will not waste any kernel-level threads.

This is correct. Your pthread_create() will use the same task_struct, which allows the threads to share file handles and static memory. Only the user stack and kernel stack are different. The threads share the same memory management structure as well. This is the only difference from a completely separate process. The context switch is light for a thread as there is no 'mm switch' which may incur all sorts of flushing. This thread_info structure can allow threads to live on different cores for SMP cases.

The thread_info is the only real structure/memory for a kernel thread. thread_info is contained in an 8K region (2 pages) which also contains the kernel stack. It is the only 'schedulable' entity by the kernel. The stack itself contains information on how to return to user space, if it is not a kernel thread.

For user space, we have additional structures which the thread_info has pointers to. So, it is one-to-one at least as far as thread_info goes. It is many-to-one for the other structure/data sets. Ie, the threads share them. For processes, they are typically one-to-one (not for fork(), but execv() type calls).

artless noise
  • 21,212
  • 6
  • 68
  • 105