[Linux] volatile | SIGCHLD | multithreading concept

1. volatile

In vscode, create signal.c file

Intentionally not writing a code block in while, so that the compiler thinks that in main, quit will only be detected


After running the executable program, when the No. 2 signal is input, call the custom method to set quit to 1, and jump out of the while loop


compiler optimization

The compiler has a corresponding compilation optimization level -O1 -O2 -O3

In the makefile, add the optimization level of -O2


When the executable program is executed again, the No. 2 signal is input, and only the corresponding custom method is called, indicating that the while loop in main cannot be stopped


insert image description here

The global variable is loaded into the memory
while loop judgment is actually a kind of calculation. When the CPU executes the calculation
, the data in the memory is loaded to the register in the CPU, and then the true or false judgment of quit is carried out
in the memory. With the code and data of the current process, there is a corresponding PC pointer in the CPU to point to.
If the while loop condition is satisfied, the pc pointer continues to point to the code of the while loop


insert image description here

If the while loop condition is not satisfied, the pc pointer will move down to point to the next statement, and execute backward


Normally, the process of loading data from the memory to the CPU is tried every time.
The quit in the main function is not modified, but only detected. If the compiler finds that the quit variable has not been modified, it will not repeatedly load the data from the memory. To the CPU
, so the compiler will optimize, only need to load the data from the memory to the CPU for the first time, and then only need to detect the data in the register

insert image description here
So at the beginning, quit is 0, and 0 is passed to the CPU. After inputting the signal No. 2, the custom method is called, and quit becomes 1,
but the quit is still 0 in the CPU, and the quit in the memory is modified. Quit cannot affect the quit of the memory.
Use quit to be 0 all the time, so the while loop cannot exit


So tell the editor to ensure that every time you detect, you must read data from the memory, and don't use the data in the register. In
order to solve this problem, use volatile

Make quit a volatile-modified global variable
volatile function: prevent register-level optimization of the quit variable to ensure memory visibility


Run the executable program again, input the No. 2 signal, jump out of the while loop, and execute printf printing in main

2. SIGCHLD signal

The child process will exit when it is running. If the parent process does not care about the exit of the child process, the child process will become a zombie. The parent process must
use wait/waitpid to wait for the child process to recycle the zombie, and obtain the exit result of the child process,
that is, the parent process blocks Waiting (do nothing, just wait for the exit result of the child process)
the parent process actively detects -------- because the child process has exited, the parent process does not know for the time being


When the child process wants to exit, it will send a signal SIGCHLD to the parent process. The
parent process's processing action for the signal is SIG_DFL and does nothing.

Verify the existence of SIGCHLD

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
pid_t id;
void handler(int signo)
{
    
    
    sleep(5);
    printf("捕捉到一个信号:%d,who:%d\n",signo,getpid());
    //-1代表等待任意一个子进程
    pid_t ret=waitpid(-1,NULL,0);
    if(ret>0)
    {
    
    
        printf("wait success,ret:%d,id:%d\n",ret,id);
    }
}
int main()
{
    
    
    signal(SIGCHLD,handler);//自定义捕捉
   id=fork();
  if(id==0)
  {
    
    
    //子进程
    int cnt=5;
    while(cnt)
    {
    
    
        printf("我是子进程,我的pid是:%d,ppid:%d\n",getpid(),getppid());
        sleep(1);
        cnt--;
    }
    exit(1);
  }

  //父进程
  while(1)
  {
    
    
    sleep(1);
  }

    return 0;
}



Implement a custom method. When the child process exits, it will send a signal SIGCHLD to the parent process
to call the corresponding custom method, and print out the corresponding signal and the pid value of the parent process.


After running the executable program, the pid value of who is the pid value of the parent process.
Signal No. 17 is SIGCHLD.
At the same time, the pid value returned by waitpid is the same as the pid value of the child process.


Create 10 child processes through the for loop. If 10 child processes send signals, the processing signals need to be processed one by one, so when a signal is sent, it may be temporarily reserved, but the parent process only has one bit pending bitmap to reserve the signal. When When the signal is retained again, the pending bitmap is set to 1 again
, overwriting the last signal, resulting in signal loss, and the final signal processing may be less than the number of sent signals


insert image description here
How many sub-processes there are, just recycle several times, if there are no sub-processes, just exit

3. Multithreading

multithreading concept

1. A thread is an execution branch with a finer execution granularity than a process, and the scheduling cost is lower.
2. A thread is an execution flow inside a process.
3. A thread is the basic unit of CPU scheduling, and a process is a basic entity responsible for allocating system resources.


These concepts will be analyzed below


understand concepts

what is multithreading

insert image description here
When a child process is created, only the PCB is created, and the created PCB continues to point to the address space of the parent process.
Assuming that there are many functions in the code area, letting different PCBs execute different functions
is equivalent to including multiple execution flows in one process, pointing to the same Different code areas in a process
Each PCB is a separate
thread The thread runs in the address space, so the thread belongs to the process


Low scheduling cost

If the same address space and page table are used between multiple threads , if it is a new process, you need to find the new address space and page table again and switch


principle of locality

There is a hardware cache inside the CPU


Preload part of the data into the buffer to improve the efficiency of the whole machine. For
example, if the CPU is accessing the 100th line of code, there is a high probability that the CPU will access the 101st line in the future,
so once the 100th line is accessed, all the data near the 100th line will be loaded into the In memory or in CPU cache


When multiple threads execute code and data, they still belong to this process, and the cache in the CPU will cache various data


insert image description here
If the thread is switched, because they all belong to the same process, the data cached in the cache will not change


insert image description here
If process switching is performed, the current cached data is set to invalid, and the cache needs to reload the current code and data

The scheduling cost is lower, which is reflected in the fact that there is no need to switch the cache

what is a process

insert image description here
task_struct is called the execution flow
. A process contains a large number of execution flows, address spaces, page tables, and the code and data corresponding to the process.
Therefore, a process is the basic entity responsible for allocating system resources.

Guess you like

Origin blog.csdn.net/qq_62939852/article/details/130693696