OS Design: Threads and dispatcher

Programmers are people who write programs. Have you ever thought about where and in what form programs are presented in operating systems? In this article, we will learn what processes and threads are, how the OS manages them.

Windows, Linux and Mac OS

This article intersects with programming, so let’s also consider some example code. Today we have a classic object-oriented programming language — Java.

Processes and threads

Open the Task Manager — you will see the processes tab. You can see the familiar programs such as Discord, Firefox, and etc.

gnome-system-monitor
Task Manager

Process is the currently executing program.

Any program consists of a process, and sometimes in addition from several more threads.

Thread is the smallest unit of processing from the OS point of view.

We can complement this definition by saying that a thread is a subprocess and depends on it. In fact, the process is sometimes called the main thread. Java monitors every thread, so the program cannot terminate until all threads have stopped.

There are daemons threads — these are low priority threads that continue to run even after the program ends.

Most often, daemons are used to free resources. The garbage collector in Java is just a daemon thread.

How does a process differ from threads:

  1. A thread is part of a process, not a separate entity
  2. Switching between threads is much faster than between processes
  3. A thread uses only one memory address space In Java, a process and threads are represented as objects of the Thread class

Let’s check the code below:

public class Application {public static void main(String[] args) {

// Get the current thread object

// And then get his name
String name = Thread.currentThread().getName();

// Print the name to console
System.out.printf("Thread's name is: %s", name);
}
}

Program’s output is shown below:

Process is the thread called “main”

Any process and thread has the following data:

  1. ID
  2. Name
  3. Priority
  4. IsDaemon flag
  5. Stacktrace
  6. Mutex (a flag that shows the current lock status: locked or unlocked)
  7. Pointers to allocated memory
  8. I/O status information
  9. other information Java implements mechanisms for getting and editing master data.

In the text below I will call the process a thread. Let’s see an example:

import java.util.Arrays;public class Application {
public static void main(String[] args)
throws InterruptedException {

// Create a thread which infinitely prints "Hello!"
Thread thread = new Thread(
() -> {
Thread current = Thread.currentThread();
while (!current.isInterrupted()) {
System.out.println("Hello!");
}
}
);

// Start the thread
thread.start();

// Call the main thread to sleep for 1 ms
Thread.sleep(1);

// Interrupt the thread
thread.interrupt();
// Print thread's information System.out.printf(
"Thread's name is: %s%n",
thread.getName()
);
System.out.printf(
"Thread's ID is: %d%n",
thread.getId()
);
System.out.printf(
"Thread's priority is: %s%n",
thread.getPriority()
);
System.out.printf(
"Thread's state is: %s%n",
thread.getState().name()
);
System.out.printf(
"Thread's isDaemon flag is: %b%n",
thread.isDaemon()
);
System.out.printf(
"Thread's stacktrace is: %s%n",
Arrays.toString(thread.getStackTrace())
);
}
}

Program’s output is shown below:

Thread’s information

Dispatcher and thread’s states

When you open the task manager, you see a large number of processes, often you can count more than a hundred processes, and the number of threads sometimes reaches a thousand. And you are wondering how the operating system manages so many processes and threads.

To handle a large number of threads, every OS contains dispatcher. Its structure is quite complex, but the main idea can be represented in this diagram (start reading by creating a process or thread):

How dispatcher works (also thread’s life cycle)

To better understand the operation of the dispatcher, let’s consider the states of threads.

In Java, as in other programming languages, there are only 6 of them:

Inner enum State contains 6 states of java’s Thread objects

Let’s take a step-by-step look at the diagram:

  1. The thread is first created as an entity (NEW)
  2. Threads are processed one at a time and wait in queues for most of their lives
  3. There are two such queues in total: for the blocked (BLOCKED) and for those ready to start (WAITING)
  4. After the thread has waited for its turn, it runs for a fixed amount of time. Then the it can follow 4 paths:
  5. If the thread is fully executed, it ends its life cycle and is unloaded from memory (TERMINATED)
  6. If there is not enough time for full execution, the thread is suspended and sent to the “Ready” queue (WAITING)
  7. If the thread was blocked, then it is sent to the “Blocked queue” (BLOCKED)
  8. If the thread was purposefully put to sleep for a certain period of time (TIMED_WAITING), then after this period, the thread is again sent to the “Ready” queue

What is the difference between a “Ready” thread and a “Blocked” thread?

The first thread is just waiting for its turn, and the second was blocked by some resource and is waiting for this resource to be released. For example, there is a hard disk, and threads use its resource (for example, they write something to the log). Since the disk cannot accept parallel writing due to its physical device, one thread writes something to the log, and the rest are blocked.

Sources

This article is based on my previously made article in VK Unix Power group.
Source

throw new NoSuchElementException("Bio is not found");