Linux server network concurrency, detailed interpretation of network IO and thread process relationship

1. Process control

1.1 Program address space

Here are some concepts that might change your perception, so take your time.

Spatial layout:

Code segment: store the MACHINE instructions executed by the CPU. Usually the code area is shareable (that is, it can be called by other executants) because for frequently executed programs, only one copy of the code is needed in memory. Code areas are usually read-only to prevent a program from accidentally modifying its instructions. In addition, information about local variables is planned in the code area. Data: Holds initialized global variables, static variables (both global and local), and constant data (such as constant strings). Uninitialized data BSS: Stores uninitialized global variables, uninitialized static variables, global variables initialized to 0, and static variables initialized to 0. Heap area: used for dynamic memory allocation, growing upwards. Stack: the compiler automatically allocates and releases the stack to store local variables, function parameters, return data, etc. It grows downward.

Let me make a correction here. What we usually call the address space of a program is actually the virtual address space of a program.

The relationship between the program virtual address space and the memory pointer: the memory pointer points to the program virtual address space, as shown in the figure

I don’t think you understand that at this point, so LET me give you an example.

1. Define global variable g_val = 100

2. The parent creates a child process

3. Print the values and addresses of global variables in the parent process

Prints the values and addresses of global variables in the child process

#include <stdio.h>
#include <unistd.h>

int g_val = 100; // Define a global variable

int main(a)
{
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork"); // Standard error
        return 0;
    }
    else if(pid == 0)
    {
        / / the child process
        printf("I'm a child process, g_val = %d, &g_val = %p\n",g_val, &g_val);
    }
    else 
    {
        / / the parent process
        printf("I'm the parent process, g_val = %d, &g_val = %p\n",g_val, &g_val);  
    }
    return 0;
}
Copy the code

The results are as follows

Super detailed summary of Linux process control, you sure don’t want to come in? We find that the values and addresses of the variables in the parent and child processes are exactly the same, which makes sense because the child processes follow the parent’s template, and the child processes do nothing to the variables. Then we change the code a little bit:

#include <stdio.h>
#include <unistd.h>

int g_val = 100; // Define a global variable intmain()
{
    pid_t pid = fork();
    if(pid < 0) { perror("fork"); // Standard error return0;
    }
    else if(pid == 0) {// child process printf(" I'm a child process, g_val = %d, &g_val = %p\n",g_val, &g_val);
    }
    else 
    {
    	g_val = 0; Printf (" I am the parent process, g_val = %d, &g_val = %p\n",g_val, &g_val);  
    }
    return 0;
}
Copy the code

The results are as follows

Super detailed summary of Linux process control, you sure don’t want to come in? The principle is shown in the figure below:

The values of the parent and child processes have changed, but their addresses are still the same. Therefore, we can draw the following conclusions:

conclusion

The contents of variables are different. So it’s definitely not the same variable that the parent and the child are putting out and the address is the same, so it’s definitely not a physical address and in Linux, it’s called a virtual address and all the addresses that we see in C/C ++ are virtual addresses, not physical addresses, Unified management by the OS The OS converts virtual addresses into physical addresses

Super detailed summary of Linux process control, you sure don’t want to come in?

1.2 Converting a Virtual Address to a physical Address

1, paging

Page number + intra-page offset

Pages: 512 bytes ~ 8KB, usually 4096 bytes (4K)

Page number = Virtual address/page size

Intra-page offset = virtual address % Page size

Super detailed summary of Linux process control, you sure don’t want to come in? 2. Piecewise

Segment number + intra-segment offset

Super detailed summary of Linux process control, you sure don’t want to come in? Segment number + page number + in-page offset By combining the above two figures, I don’t need to know much about it, so I won’t draw it

1.3 Other concepts

1. Run-time preemptive execution between processes

When a child process is created using fork, the parent and child processes execute their code preemptively.

Parallelism and concurrency

Parallel: Multiple processes running on different cpus at the same time are called parallel

Concurrency: Multiple processes can only have one CPU at a time to perform operations. This is called concurrency

3. Independence: Multiple processes need to enjoy all kinds of resources and do not interfere with each other during the operation of multiple processes

2. Create a process

2.1 Copy-on-write

Parent and child processes share code, data is unique. When either party tries to write, a copy is made in the form of a copy on write, and whoever changes points to the copy (because this is a new space, called a deep copy).

3. The process terminates

3.1 Process Termination Exit scenario

So if the code is running and the result is correct the code is running and the result is not correct the code is terminated abnormally by echo $? View the process exit code

Common exit methods

Main function return Exit CTRL +c kill -9 Process id/process name exit function _exit function 3.2exit function and _exit function exit function

Void exit(int status) Library function

Who calls who exits

Status: indicates the exit status code of the process

The inside of the exit function wraps the _exit function.

The exit function does two more things to exit the process than the _exit function:

1. Run the user-defined cleanup function

2. Refresh the buffer

** _exit function **

Void _exit(int status) System call function

Who calls who exits

3.3 Brief introduction to the callback function atexit

Int atexit(void (*function) (void)); The argument is a function pointer type, and it receives the address of a function. The function returns void, and the argument is also void

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

void myhome(void)
{
     printf("i want to go home\n");
 }
 
 int main() { atexit(myhome); printf("hello world! \n"); return0;
 }
Copy the code

The results are as follows

Super detailed summary of Linux process control, you sure don’t want to come in? The reason is that atexit registers a function myHome, not a call. The myHome function that you just registered is called when main is finished.

3.4 Refreshing the Buffer

Fflush: Force the \n exit function to refresh after the return from main

4. The process waits

role

The parent process calls the method that the process is waiting for and waits for the child process to exit, preventing the child process from becoming a zombie process

methods

4.1 wait function

The prototype of the function is

#include <sys/types.h> #include <wait. H > int wait(int *status) Once the parent process calls wait, it blocks itself immediately. Wait automatically analyzes whether a child process of the current process has exited. If it finds such a child process that has become zombie, wait collects information about the child process, destroys it thoroughly and returns. If no such child is found, wait blocks at this point until one appears.

Parameters:

Output parameter: returns the result of the internal calculation of the wait function to the caller via status

Input parameters: parameters passed by the caller to the called function

Input/output parameters

The status value returned

Successful PID failure -1

Status Outgoing parameter

Block waiting child process

Reclaim child process resources

Obtain the child process end status:

1) true

WEXITSTATUS () Gets the child process exit status

Wait on their wait, signaled ()

WTERMSIG () gets the encoding of the signal that causes the child process to terminate

Only the lower 16 bits of STATUS are studied

4.2 waitpid function

The same as wait, but you can specify pid process cleanup, can not block.

Pid_t waitPID (pid_t pid,int *status,int options) Successful: the cleared child process PID is returned. Failure: -1 (no child process)

Special arguments and returns:

The pid parameters:

0 Reclaims the child process with the specified ID

-1 Reclaim any child process (equivalent to wait)

Reclaim and currently call waitpid a group of all child processes

< -1 Reclaims any child process in the specified process group

Return 0: argument 3 is WNOHANG and the child process is running.

Note: A wait or WaitPID call can only clean up one child process. Cleaning up multiple children requires a loop

5. Process replacement

5.1 Process replacement principle

Replace the code and data segments of the current process with the new program and update the stack. Note: When the process program is replaced, the process is executing the new program, but the process number is unchanged

5.2 Process replacement functions

The exec function cluster

#include <unistd.h> int execl(const char *path, const char *arg,...) ; Int execlp(const char *file, const char *arg,...) ; Int execle(const char *path, const char *arg,... ,char *const envp[]); int execv(const char *path, char *const argv[]); int execvp(const char *file, char *const argv[]); int execve(const char *path, char *const argv[], char *const envp[]);Copy the code

File: Executable program to be replaced, you can not give a path (but the executable program to be replaced must be searchable in the path environment variable). Arg: the command-line argument passed to the executable argv[]: an array of Pointers that hold the arguments passed to the executable note: The first element of the array should be the executable itself and the last element of the array should be NULL envp[]: The programmer organizes environment variables and the last argument is NULL

The return value:

If the replacement succeeds, there is no return value; Because once the replacement is successful, the other program is executed.

If the replacement fails, the return value is -1

The first five functions are library functions that depend on the system call function execve.

5.3 Application Scenarios of the Process Replacement function

1. Bash application scenarios

2. Daemon process

Daemons are special processes that run in the background to perform specific system tasks. Many daemons start at system boot time and run until the system is shut down. Others start only when needed and automatically end when the task is completed

Role: Protects service processes

1. The service process is not started directly. Instead, start the daemon

2. Let the daemon process, create a child process, let the child process process to replace the business process.

3. The daemon process communicates with the service process so that the daemon process can know the status of the service process

If the service process is normal, the daemon process does not perform the operation

If the business process crashes, or is abnormal, the daemon pulls up a child process again, allowing the child process to perform process program replacement

That’s the point of this post, and that’s it for today.