I understand that regarding the kernel-level threads, there is an interrupt caused by reaching a certain cycle count, that is signaling the kernel to perform the required context switch over to another thread depending on the scheduler.
In my understanding regarding user-level threads, in a many to one model the scheduling of the user threads is done completely in user space. The kernel just schedules the kernel thread user-level threads had been mapped to.
My problem is that I can't comprehend the bit after "the control has been transferred to a certain user-level thread". How does it cease to execute for the scheduler to get the control back to perform needed context switching and selecting of another thread for execution? I am not sure if there are any timer registers being used to cause an interrupt when it comes to user-level threads.
So once again how does the user-level scheduler get the control back?
Please enlighten me.
Funny thing (what a real coincidence) I've been formulating the answer to this in my head on my way home yesterday. For real.
The answer is that user-level thread has to give control back. Only kernel-level threads could be preempted. This control giving can happen either explicitly - by calling functions like yield() - or implicitly, by calling any other function which know how to transfer control. Those would be most likely thread-synchronization functions.
Related
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.
I have some confusion regarding user-level thread blocking. As we know that one user-level thread blocking leads to the whole process being blocked, then why is "responsiveness" one of the benefit of multi-threading? Given in the book of Silberschatz "Operating System Concepts":
Multithreading in interactive application may allow a program to
continue running even if part of it is blocked or is performing a
lengthy operation, thereby increasing responsiveness to the user.
Is this referring to kernel-level threads only or is there something i am not able to understand?
So, the question is, how can responsiveness be an advantage of threads, when one user-level thread blocking results in entire process being blocked?
So, the question is, how can responsiveness be an advantage of threads, when one user-level thread blocking results in entire process being blocked?
User-level threads only block under two circumstances:
When they hit a page fault or some other condition that the threading library can't handle.
When the entire process has no way to make forward progress.
This is the primary job that a user-level threading implementation has -- to take functions that would normally block and replace them with non-blocking versions so that other user-level threads can make forward progress.
That still means that if any user-level thread hits a page fault, the entire process cannot make forward progress until the page fault is serviced.
With user-level threading, the actual threads NEVER block -- any operation that might block is instead intercepted and the non-blocking equivalent done instead. If the user level thread DID block, as you note, it would inadvertantly block other threads, which is broken.
I have some confusion regarding user-level thread blocking. As we know that one user-level thread blocking leads to the whole process being blocked, then why is "responsiveness" one of the benefit of multi-threading?
That is only true on some operating systems.
So, the question is, how can responsiveness be an advantage of threads, when one user-level thread blocking results in entire process being blocked?
The systems widely in use when "user threads" were developed often had software interrupts that prevented the entire thread from being blocked.
Now, any operating system worth its salt has real threads and "user threads" are a relic of the ages and operating systems that have not kept up.
Keeping my question short... i am writing simulation for a RTOS. As usual the main problem comes with context switch simulation. In case of interrupts it is really becoming hard not to deviate from 'Good' coding guidelines.
Say Task A is running and user application is calculating its harmless private stuff which will run for a long time. during this task A, an interrupt X is supposed to occur. (hint: task A has nothing to do with triggering this interrupt X)... now how do i perform context switch from Task A to interrupt X handler?
My current implementation is based on a context thread that waits till some context switch is requested; an interrupt controller thread that can generate interrupts if someone request interrupt triggering; and a main thread that is running Task A. Now i use interrupt controller thread to generate a new thread for interrupt X and then request context thread to do the context switch. Context thread Suspends Task A main thread and resumes interrupt X handler thread. At the end of interrupt X handler thread, Task A main thread is resumed..
[Edit] just to clarify, i already know suspending and terminating threads from outside is really bad. That is why i asked this question. Plus please don't recommend using event etc. for controlling Task A. it is user application code and i can't control it. He can even use while(1){} if he wants...
I suspect that you can't do what you want to do in that way.
You mentioned that suspending a thread from outside is really bad. The reason is that you have no idea what the thread is doing when you suspend it. It's impossible to know whether the thread currently owns a mutex; if it does then any other thread that tries to access the same mutex is going to deadlock.
You have the problem that the runtime being used by the threads that might be suspended is the same as the one being used by the supervisor. That means there are many potential such deadlocks between the supervisor and the other threads.
In a real environment (i.e. not a simulator), the operating system kernel can suspend threads because there are checks in place to ensure that these deadlocks can't happen. I don't know the details, but it probably involves masking interrupts at certain critical points, and probably not sharing the same mutexes between user-mode code and critical parts of the kernel scheduler. (In your case that would mean your scheduler could not use any of the same OS API functions, either directly or indirectly, as are allowed to be used by the user threads, in case they involve mutexes. This of course would be virtually impossible to achieve.)
The reason I asked in a comment whether you have any control over the user code compiler is that if you controlled the compiler then you could arrange for the user code to effectively mask interrupts for the duration of each instruction and only yield to another thread at well-defined points between instructions. This is how it is done in a control system that I work on.
The other aspect is platform dependence. In Linux and other unix-like operating systems, you have signals, which are like user-mode interrupts. You could potentially use signals to emulate context switching, although you would still have the same problem with mutexes. There is absolutely no equivalent on Windows (as far as I know) precisely because of the problem already stated. The nearest thing is an asynchronous procedure call, but this will run only when the thread has put itself into an alertable wait state (which means the thread is in a deterministic state and is now safe to interrupt).
I think you are going to have to re-think the whole concept so that your supervisory thread has the sort of privileged control above the user threads that the OS has in a non-emulated environment. That will probably involve replacing the compiler or the run-time libraries, or both, with something of your own making.
I'm studying threads and I am not sure if I understand some concepts. What is the difference between preemption and yield? So far I know that preemption is a forced yield but I am not sure what it actually means.
Thanks for your help.
Preemption is when one thread stops another thread from running so that it may run.
To yield is when a thread voluntarily gives up processor time.
Have a gander at these...
http://en.wikipedia.org/wiki/Preemption_(computing)
http://en.wikipedia.org/wiki/Thread_(computing)
The difference is how the OS is entered.
'yield' is a software interrupt AKA system call, one of the many that may result in a change in the set of running threads, (there are lots of other system calls that can do this - blocking reads, synchronization calls). yield() is called from a running thread and may result in another ready, (but not running), thread of the same priority being run instead of the calling thread - if there is one.
The exact behaviour of yield() is somewhat hardware/OS/language-dependent. Unless you are developing low-level lock-free thread comms mechanisms, and you are very good at it, it's best to just forget about yield().
Preemption is the act of interrupting one thread and dispatching another in its place. It can only occur after a hardware interrupt. When hardware interrupts, its driver is entered. The driver may decide that it can usefully make a thread ready, (eg. a thread is blocked on a read() call to the driver and the driver has accumulated a nice, big buffer of data). The driver can do this by signaling a semaphore and exiting via. the OS, (which provides an entry point for just such a purpose). This driver exit path causes a reschedule and, probably, makes the read thread running instead of some other thread that was running before the interrupt - the other thread has been preempted. Essentially and simply, preemption occurs when the OS decides to interrupt-return to a different set of threads than the one that was interrupted.
Yield: The thread calls a function in the scheduler, which potentially "parks" that thread, and starts another one. The other thread is one which called yield earlier, and now appears to return from it. Many functions can have yielding semantics, such as reading from a device.
Preempt: an external event comes into the system: some kind of interrupt (clock, network data arriving, disk I/O completing ...). Whichever thread is running at that time is suspended, and the machine is running operating system code the interrupt context. When the interrupt is serviced, and it's time to return from the interrupt, a scheduling decision can be made to keep the interrupted thread parked, and instead resume another one. That is a preemption. If/when that original thread gets to run again, the context which was saved by the interrupt will be activated and it will pick up exactly where it left off.
Scheduling systems which rely on yield exclusively are called "cooperative" or "cooperative multitasking" as opposed to "preemptive".
Traditional (read: old, 1970's and 80's) Unix is cooperatively multitasked in the kernel, with a preemptive user space. The kernel routines are trusted to yield in a reasonable time, and so preemption is disabled when running kernel code. This greatly simplifies kernel coding and improves reliability, at the expense of performance, especially when multiple processors are introduced. Linux was like this for many years.
Can someone give me an easy to understand definition of kernel thread dispatching or just thread dispatching if there's no difference between the two?
From what I understand it's just doing a context switch while the currently active thread waits on a lock from another thread, so the CPU goes and does something else while this thread is in blocking mode.
I might however have misunderstood.
It's basically the process by which the operating system determines which of the many active threads is sent (dispatched) to the CPU for processing at any given point.
Each operating system has its own implementation, but the basic concept is to keep a sorted list of threads by priority, and dispatch them as needed to the CPU. Time slicing is added to allow multiple programs to run concurrently, etc.