Let's assume you have an OS that tries to run threads in round-robin scheduling. I know there are two instances when the OS will try to switch between multiple threads: (there could be more...)
- When the current thread actually yields the CPU earlier on its own.
- When the OS receives a timer interrupt. The question is let's say the OS has a max compute-bound time of say 5ms. (the OS receives a timer interrupt every 5ms)this assumption means that each thread can own a CPU core for a maximum of 5ms.
What happens if a process/thread finishes its time slice earlier than 5ms? Will this cause the next thread to be scheduled to have a compute-bound time lesser than 5ms since the next timer interrupt will occur and the thread will have no choice but to give up the CPU?
Specific Example:
What happens if a process/thread finishes its time slice earlier than 5ms let's say 2ms?
I know another thread will be scheduled, but will that thread have a full-time slice of 5ms or will this next thread only have 3ms before the next timer interrupt occurs?
CodePudding user response:
This question is likely dependent of the OS (not provided). On mainstream OSs, a yielding tasks typically waits for a resource or for a given time. The operating system will not reschedule it unless it becomes ready (completed IO operation, available lock, timeout, etc.). When a new task is ready, the OS scheduler is free to either wait for the end of a time-slice or reschedule the previous task. It is common for the task to be rescheduled so to increase the responsiveness of multithreaded applications (waiting for few milliseconds when a code tries to hold a lock that is already taken is not reasonable). That being said, this behavior is often not implemented so directly. Windows make use of priority boosts so to do that. On Linux, CFS tries to make the schedule fair so that all tasks have a balanced time on all available resources (eg. cores). The priority of the target tasks also matters. The OS of some famous gaming consoles uses a round-robin scheduler by default and they only schedule lower-priority tasks if there is no high-priority task. On such system, when a higher-priority task becomes ready, the current one is directly interrupted (with not delay except the overhead of a context switch).
Put it shortly, the OS does not necessary have to wait for a timer interrupt to do context switches. Also, yes, time-slices are generally never left empty so they are reused by other tasks. Whether the scheduled tasks can be scheduled in a full time slice is dependent of the actual OS scheduler. Also note that a thread do not "give up the CPU": user-land threads have not real control on this. In practice, either a schedule
-like kernel call is done during a system call (causing a context switch of the current task), or a system interrupt causes a kernel code to be executed that typically do this schedule
-like kernel call at the end of a time slice.
CodePudding user response:
There are a lot of ways threads can yield, e.g. posting or waiting on a semaphore, input, output, etc. If a thread yields, or it's scheduling timer times out (5ms), the OS will rummage through the list of threads to see what else can be run.
That rummaging literally involves running through the list of threads and seeing what their status is.
- Some threads may be listed as "preempted" (i.e. they hadn't yielded, the OS 5ms scheduling timer timed out and the OS had suspended them in favour of another) in which case one of those can simply be reinstated (registers restored, program counter set, CPU picks up from that point). Round Robin scheduling is simply an extra piece of information, namely "When did this thread last get run?", the OS favouring the thread that's not been run for longer than all the others.
- Others will be listed as waiting on I/O (so those can't be run), and yet more will be listed as waiting on locks like semaphores (so those can't be run either).
- Note that something like a sem_post() is also a yield, giving the OS a chance to do this rummaging, perhaps finding a thread that is listed as waiting on the semaphore that's just been posted.
If an OS determines that across all processes there are no runnable threads at all (nothing waiting on semaphores, everything hung up waiting for I/O), and there is nothing for it to do itself, what happens next depends on the CPU. For some older CPUs, the OS would literally have to enter an infinite loop waiting for some interrupt to fire from some device. More modern CPUs have an instruction which will suspend execution until some interrupt fires.
Basically, the OS scheduler is part interrupt service routine (responding to timer or device interrupts), and part "ordinary" code that simply manages lists of threads when threads voluntarily yield.