## A history of concurrent programming

In the early operating system, the execution of each task was completely serial, and only after the completion of one task, another task would be executed, which we call 单道程序.

The 多道程序concept of concurrency introduced by modern operating systems :

Multi-program: When a program does not need to use the CPU for the time being, the system will suspend or interrupt the program. At this time, other programs can use the CPU. Multiple tasks achieve macro-concurrency under the control of the operating system. UndefinedMulti-programs improve the utilization of computer resources, but also cause multiple tasks to grab system resources, which is extremely inconvenient in development.

## 2. Computer terminology

### 2.1 Serial and Concurrency

Serial and concurrency are concepts of the same dimension, the difference is:

• Serial: instructions are executed in sequence
• Concurrency: The instructions are not executed in sequence, but are executed at the same time on a macro level, that is, the CPU keeps switching back and forth between tasks, giving people the impression that all tasks are executed at the same time! For example, the computer is running QQ and browser at the same time, but the CPU is actually switching back and forth between these two programs according to a certain scheduling algorithm!

Parallel and concurrency are not concepts in the same dimension:

• Parallel (parallel): At the same time (microsecond level), multiple instructions are executed simultaneously on multiple processors. Parallel is generally achieved with the help of a multi-core CPU!
• Concurrency: It is not executed at the same time, but because the CPU is running too fast, it gives people the illusion of running at the same time

The difference between concurrency and parallelism is whether it is executed at the same time. For example, when eating, the call comes, you need to stop eating to answer the call, and continue eating after receiving the call. This is a concurrent execution, but the call comes during the meal, and the answer is parallel while eating. .

### 2.2 Process

Process: It is the running instance of the binary executable file in the computer memory. It can be simply understood as: an .exe file is a class, and the process is a new instance of the class. A process is the smallest unit of operating system resource allocation (such as virtual memory resources), and all codes are executed in the process.

In Unix systems, after the operating system is started, a process init with a process number (PID) of 1 will be run, which is the parent process of all other processes. The operating system can create multiple child processes through the fork() function, which can improve the utilization of computer resources.

After the process is created, it will have its own independent address space. The operating system will provide a data structure PCB to describe the process (Process Control Block). The PCB stores process management and control information and other data.

Because processes have independent address spaces, they cannot communicate directly between processes, and must use InterProcess Communication (IPC, InterProcess Communication) to achieve communication.

### 2.3 Kernel mode and user mode

The operating system's memory will be divided into two major areas:

• Kernel area: Provides a large number of system call functions, that is, the most primitive and lowest-level operation functions, such as open(), write()
• User area: the area for loading and running application programs, such as programs written in C language. The same C language also provides the corresponding operation functions fopen() and fwrite() of the language. These functions provided by the programming language are called library functions.

It is not difficult to find that the library function is actually encapsulated again on the basis of the system call function, which is convenient for developers to use. Of course, developers can use library functions to manipulate files, or directly use underlying system call functions (but this requires a lot of error handling).

When the program is running, the CPU has two states:

• User mode: When a process is executing the user's own code, it is in the user mode (user mode)
• Kernel mode: When the process needs to execute some system calls, such as using the C library function fopen(), although fopen() is a library function, the bottom layer calls the system open() function during execution, and the program enters the kernel mode. , After the call is over, the program will return to the user mode!

The reason why the operating system is designed in this way is out of memory safety considerations, the kernel address can only be used by the kernel's own function (system call function)!

Thread: a lightweight process opened by the operating system based on the process, which is the smallest unit of the operating system's scheduling and execution (that is, the object to which the cpu allocates time rounds)

Multiple threads can be created within a process. They have independent PCBs like the process, but there is no independent address space, that is, the address space is shared between threads. This also allows threads to communicate directly without IPC! ! (Because they are in the same address space).

Although threads bring the convenience of communication, if multiple threads in the same space modify the same data at the same time, it will cause resource competition, which is the most complicated problem in computer programming!

### 2.5 Coroutine

Processes and threads are at the operating system level, and coroutines are not a dimensional concept with them, so books like "Modern Operating Systems" do not propose the concept of coroutines.

Tips: Do not understand coroutines as lightweight threads!

Coroutine: When the program is being executed, the function can be interrupted, and then return to the execution at an appropriate time, that is, the coroutine runs in user mode

The advantage of the coroutine lies in its light weight and high execution efficiency:

• Lightweight: There is no thread overhead, millions of coroutines can be created easily without causing system resource exhaustion
• High execution efficiency: the switch between functions is no longer a thread switch, but is controlled by the program itself

Threads need to constantly switch contexts, and the coroutine will not actively hand over the right to use, unless the code actively requires switching, or I/O occurs, at this time it will switch to other coroutines, which can better solve the concurrency problem.

## 3.concurrency theory basis

### 3.1 Concurrency solution

• Multi-process: Concurrency is managed by the system kernel, the operation is simple, and the processes do not affect each other. But the overhead is the largest, it takes up more resources, and the number of processes that can be started is very small.
• Non-blocking I/O: Asynchronous non-blocking I/O based on callbacks, using as few threads as possible
• Coroutine: In essence, it is still a user-mode thread, but does not require preemptive scheduling by the system, and the real implementation is stored in the thread with minimal overhead.

### 3.2 Concurrent program data interaction method 1: Synchronization

Thread synchronization: When a thread issues a function call, if the result is not obtained, the call does not return. At this time, other threads cannot call this function (because data consistency must be ensured).

Thread synchronization is to avoid causing data confusion. In fact, when multiple control flows work together to operate a shared resource, synchronization is required. For example, a synchronization mechanism is required among processes, threads, and signals. A common thread synchronization technique is a mutual exclusion lock.

The role of synchronization is to avoid conflicts that may occur when concurrently accessing shared resources.

Concept of synchronization:

• If a program wants to use a shared data, it must first obtain the right to use it. When the program no longer uses the resource, it should give up the right to access the resource (ie, release the resource).
• After the right to use the resource is taken away, other programs that access the resource should not be interrupted, but should wait until the program that has the right to use the resource releases the resource before accessing it. undefined means: at the same time, a certain resource should be occupied by only one program.

### 3.3 Concurrent program data interaction mode two: data transfer

In addition to using the synchronization method to realize the interaction of concurrent program data, you can also use the data transfer method (also known as communication).

In this way, the data can be sent to the data receiver without delay. Even if the data receiver is not ready to receive the data, it will not cause the data sender to wait. The data will be temporarily stored in a data structure called the communication buffer. The communication buffer is a special data structure that can be used by multiple programs at the same time, and the data receiver can receive them in the order in which the data is stored in the communication buffer after it is ready.

## 4.concurrency concepts in various languages

• Java: a typical multi-threaded concurrency mode, using synchronization mechanism (locking) to achieve concurrent access control
• Node.js: A typical single-threaded non-blocking I/O practitioner. There is no resource competition problem in Java. The event mechanism will be used to notify the business thread to return the result after the I/O operation is processed. There is no resource competition problem.
• Go: A typical practitioner of the concurrency concept of coroutines, who implements coroutines at the level of the language itself, and transfers data between coroutines through pipes .

The current popular concurrency concept is: asynchronous non-blocking I/O, coroutine.

Reference: https://cloud.tencent.com/developer/article/1631713 Concurrent Programming-Overview-Cloud + Community-Tencent Cloud