As for processes and threads, it is always said that "a process is the smallest unit of resources allocated by the operating system, and the thread is the smallest unit of operating system scheduling." This sentence is theoretically OK, let's look at what is called "resources".
What is a computer resource
The classic von Neumann structure abstracts the computer system into CPU + memory + IO, so there are two kinds of computer resources:
1. Computing Resources
2. Storage Resources
CPU is a computing unit, purely from the CPU's point of view it is a black box, it only the input instructions and data to calculate, and then output the results, it is not responsible for managing the calculation of what "instructions and data." In other words, the CPU only provides compute power, but it is not responsible for allocating compute resources.
Computing resources are assigned by the operating system, which is often said operating system scheduling module, by the operating system according to certain rules to allocate when by whom to obtain CPU computing resources, such as split time slices
Storage resources are the resources of memory, disks, these storage devices. At the bottom of this computer knowledge supplements (a) understand the virtual memory mechanism we said that the operating system uses a virtual memory mechanism to manage storage, from the point of view of the caching principle, the memory as a disk cache. The process is disk-oriented, why is it that the process represents a running program, a program's code snippet, data segments that are stored on disk and loaded into memory at run time. So virtual memory is for disks, virtual pages are allocated to disk files, and then cached to physical pages in physical memory.
So storage resources are managed and distributed by the virtual memory mechanism by the operating system. the process should be the smallest unit on which the operating system allocates storage resources.
Then look at the thread, in theory the Linux kernel is not the concept of threading, only the Kernel scheduler entity (kernal scheduling Entry, KSE) this concept. Linux threads are inherently a lightweight process that is created using the Clone system tune. What is "lightweight" will be followed up. A process is a KSE, and a thread is a KSE. So "thread is the smallest unit of operating system scheduling" that's fine.
What is a process
A process is an abstraction of a computer,
1. The process represents a logical control flow, which is a computational process that creates an illusion as if the process has been monopolizing CPU resources
2. The process has a separate virtual memory address space, which creates an illusion as if the process is consistent in the exclusive memory resource
This graph is the allocation model diagram of the virtual memory address space of the process, and you can see that the virtual memory address space of the process is divided into user space and kernel space. User space from low-end addresses to high-end address development, kernel space from high-end addresses to low-end address development. The user space holds the code snippet and data segment of the process, as well as the heap and user stack at runtime. The heap is from the low-end address to the high-end address development, the stack is from high-end address to low-end address development.
Kernel space holds the kernel's code and data, as well as the related data structures that the kernel creates for the process, such as page table data structures, task data structures, area region data structures, and so on.
From the point of view of file IO, Linux abstracts all IO into files, such as normal file IO, network io, all files, and using the open system call to return an integer as the file descriptor, descriptor, the process can take advantage of file Descriptor represents the open file as a parameter in any system call. The kernel maintains a file descriptor table for the process to maintain all the files descriptor the process obtains.
Each call to the open system call to the kernel creates an open file data structure to represent the open file, recording the current location of the file and other information. Opens the file with a single pointer pointing to the INODE structure of the file in the file system. The Inode records the file name, path, access permissions, and other metadata for the file.
The operating system uses 3 data structures to manage the file resources it opens for each process
Fork system Call
The operating system uses the fork system to create a sub-process. The child process created by fork copies the virtual address space of the parent process.
To understand the difference between "copy" and "share", copying means actually copying a copy of the content in physical memory, which actually consumes the new physical memory. Sharing means that using pointers to the same address does not really consume physical memory. It is important to understand the difference between these two concepts, which is one of the fundamental differences between processes and threads.
So someone asked, if my parent process takes up 1G of physical memory, will fork use 1G of physical memory to replicate, equivalent to using 2G of physical memory?
The answer is that the earlier operating system did this, but the performance is too poor, so the modern operating system uses copy on write to optimize the performance of the fork, fork just created the child process is shared, only pointer to the parent process's physical resources. When a child process actually writes to some physical resource, it actually replicates a piece of physical resources for the child process to use. This greatly optimizes the performance of the fork, and logically the child process has a separate virtual memory space.
Fork not only copied the page table structure, but also copied the parent process's file descriptor table, signal control tables, process information, register resources, and so on. It is a more in-depth copy.
From the point of view of the logical control flow, thesub-process created by fork begins execution where the fork function returns . This is not the same as threading, and we know that thread in Java needs to write the Run method, and the thread starts executing from the Run method.
Now that we know that the kernel maintains so many resources for the process, the process context switches that are made when the memory is scheduled for the process are easy to understand, and a process that relies on all of these resources, the process context switch will save these resources and write them back into memory. The next time this process is dispatched, the resources are then loaded into registers and cache hardware.
The contents of the process context switch save are:
Page table--Corresponding virtual memory resources
File descriptor Table/Open File tables-corresponding open file resources
Register--corresponding to runtime data
Signal control information/process run information
Inter-process communication
The virtual memory mechanism brings benefits to process management storage resources, but it also gives the process a little bit of trouble, knowing that each process has a separate virtual memory address space and sees the same virtual internal address space view, so for different processes, an identical virtual address means a different physical address. We know that the CPU executes the instruction with a virtual address, which corresponds to a specific virtual address for a particular variable. The problem is that two processes cannot communicate inter-process through simple shared variables, that is, processes cannot communicate between processes by directly sharing the memory, only using signals, pipelines, and so on for interprocess communication. Such efficiency is certainly worse than the way directly shared memory
What is a thread
It says a bunch of what resources the kernel allocates for the process, we know that the process manages a bunch of resources, and each process has a separate virtual memory address space that really has physical memory that is separate from the parent process. And because the process has a separate memory address space, the process cannot use direct memory mapping for interprocess communication.
The essence of concurrency is multiple logical flows that overlap over time, that is, multiple logical flows that run concurrently. One of the most important problems to solve in concurrent programming is the problem of concurrent access to resources, that is, the problem of shared resources. and two processes are very difficult to logically represent shared resources.
The biggest problem with threading is that it can simply represent a shared resource, where the resource is the memory resource, and the resource is eventually loaded into physical memory, and all threads of a process share the same virtual address space of the process, that is, from the thread's point of view, The physical resources they see are the same, so that shared resources can be represented by shared variables, that is, the direct sharing of memory solves the problem of thread communication. The thread also represents a separate logical flow, which perfectly solves a big problem with the process.
After understanding threads from the perspective of storage resources, it is not difficult to understand the allocation of computing resources. From the point of view of computing resources, there is no difference between a process and a thread for the kernel, so the kernel uses the Kernel scheduler entity (KSE) to represent a scheduled unit.
Clone system call
In a Linux system, a thread is called with a clone system, and clone is a lightweight fork that provides a series of parameters that indicate what resources a thread can share in a parent class, such as a page table, open a file table, and so on. As we said above, the difference between sharing and replication is that sharing simply points to the same physical address and does not open new physical memory outside of the parent process.
The clone system call can specify that the created thread begins execution of the code location, which is the thread class's Run method in Java.
The Linux kernel only provides the concept of clone, a lightweight process that the system is using to create threads like this. The C language uses the Pthreads library to really create a thread of this data structure. Linux employs a 1:1 model, that is, the thread entity 1:1 created by the C-pthreads library corresponds to a KSE created by the kernel. Pthreads runs in user space, KSE runs in kernel space.
Now that the thread has shared the resources of the process, the context switch for the thread is understandable. For the operating system, it sees that the thread to be dispatched and the thread that is running is the same process, so the context switch of the thread only needs to save some runtime data of the thread, such as
The ID of the thread
The value in the Register
Stack data
Instead of saving data such as the page table, file descriptor tables, signal control data, and process information, like the process context switch. Page table is a very heavy resource, as we have said before, if the structure of the first-level page table, then the 32-bit Machine page table to achieve 4MB of physical space. So the thread context switch is very lightweight.
The process takes a parent-child structure, the INIT process is the topmost parent process, and the other processes derive from the init process. This makes it easy to understand how the process shares the kernel's code and data.
The thread takes on a peer structure, that is, the thread does not have a parent-child concept, all threads belong to the same thread group, and the group number of the thread group equals the thread number of the first thread.
Let's take a look at how Java threads are implemented. The Java language layer provides the Java.lang.Thread class to represent the Java language level of the thread, and provides a logical control flow that the Run method represents the thread running.
We know that the JVM is written by c++/c, and the JVM itself uses the Pthreads library to create the threads of the operating system. The JVM also supports the concept of threads created by the Java language.
Talk about the JVM (v) Understanding Threads from the JVM perspective this article has already said how to understand threads from the perspective of the JVM. The JVM provides the Javathread class to correspond to the Java language thread, the Java language in which a Java.lang.Thread object is created, and the JVM creates a Javathread object in the JVM accordingly. The JVM also creates a Osthread class to thread objects on the underlying operating system that the application pthreads creates.
Building concurrent programs can be based on processes or threads,
For example, Nginx is based on the process of building concurrent programs. Java, by its nature, only supports threading-based approaches to building concurrent programs.
Finally, we summarize the process vs thread
1. The process is created by fork and the thread is created with clone
2. The logical flow location of the subprocess created by the process fork in the location where the fork is returned, the logical flow location of the KSE created by thread clone in the clone call to the incoming method location, such as Java's thread's Run method location
3. The process has a separate virtual memory address space and kernel data structure (page tables, open file tables, etc.), and when a child process modifies a virtual page, a real physical page is created through a write-time copy. Threads share the virtual address space and kernel data structure of the process, sharing the same physical page
4. Multiple process communication can only take the form of interprocess communication, such as signals, pipelines, rather than simple shared memory, because each process maintains a separate virtual memory space, so the virtual address of each process variable is different. Multiple thread communication is straightforward, using shared memory directly, because different threads share a virtual memory address space, and variable addressing uses the same virtual memory
5. The process context switch needs to switch the heavy resources such as the page table, and the thread context switch only needs lightweight data such as switching registers.
6. Process user stack exclusive stack space, thread user stack share virtual memory in the stack space, no process efficient
7. An application can have multiple processes, execute multiple program code, multiple threads can execute only one program code, share a process's code snippet
8. The process uses a parent-child structure, the thread uses the peer structure
Resources
"In-depth understanding of computer systems"
The Linux system Programming manual
Computer knowledge Supplements (ii) in-depth understanding of processes and threads