Linux multi-tasking programming (1)

Preface

Why learn multi-process threading:

        Before we study this course, the execution logic of our code is executed statement by statement from top to bottom: what to do first, what to do next. Learning multi-threaded processes allows you to run multiple tasks at the same time, switching between them without affecting each other, and eliminating the shortcomings of traditional code logic execution. Tasks will be switched frequently to give users the feeling of multiple tasks running at the same time.

What is the task:

To put it simply: a task is a run of a program. A task contains one or more subtasks with independent functions. This independent subtask is a process or thread.

1. Process Basics

 1.1 The concept of process

  1.1.1 What is a process

        Process is the smallest unit of program execution and resource management. It is a dynamic concept. It is the process of program execution, including creation, scheduling and death.

  1.1.2 What is a program?

        Program: A collection of static instructions. The program is equivalent to your plan.

  1.1.3 The difference between process and program

        A program is static, it is an ordered collection of instructions stored on the disk, without any concept of execution. A process is a dynamic concept, it is the process of program execution, including creation, scheduling and death. A program can correspond to multiple A process, and a process can only correspond to one program.

  1.1.4 What does a process include?

        (1) The "data segment" stores global variables, constants, and data space allocated for dynamic data (such as the space obtained by the malloc function).

        (2) The "text segment" stores the code in the program.

        (3) The "stack segment" stores the return address of the function, the parameters of the function, and the local variables in the program.

  1.1.5 Characteristics of the process:
(1) Dynamic: It has a complete life cycle and changes dynamically during the life cycle. Also has dynamic address space
(2) Concurrency: simultaneously at the macro level, sequentially at the micro level
(3) Independence: processes do not interfere with each other unless inter-process communication is involved
(4) Asynchronous: The execution of each process is scheduled by the CPU, which may be different or the same.

  1.2 Process management methods:

        Windows: Management method: Task Manager Process handler: CPU

         linux: Management method: PCB >>Process Control Block (process management block)

 It is a method used by the Linux system to manage processes. It is a very large structure created and maintained by the kernel: struct task_struct

Process handler:CPU

  1.2.1 Task status changes

  1.2.2 Classification of processes:

(1) Interactive process: generated and controlled by the shell terminal, such as: ./a.out

(2) Batch processing process: shell script: instructions are executed batch by batch 

(3) Daemon process: periodically waits or performs a task in the background, such as: ssh samba tftp nfs Trojan

  1.2.3 Viewing the process:
 查看状态:
ps -aux   :静态查看进程
top       :动态查看进程(每三秒刷新一次)

USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

USER:进程拥有者 
PID :进程的ID号,是进程的唯一标识,不重复 :越早开启的进程,PID越小 
%CPU: CPU的占用率 
%MEM:物理内存占用率 
VSZ :虚拟内存用量 
RSS :物理内存用量        
TTY :终端的使用,如果该进程没有终端:显示? 
STAT:进程的状态 

进程状态:
S:休眠(可以中断)    D:休眠(不可中断)    I:空闲 Idie    T:暂停     X:死亡    Z:僵尸状态      R:正在运行    s:进程的领导者(多进程)     <:优先级高     N:优先级低    l:线程的领导者(多线程) +:前端进程


休眠(可中断):进程处于阻塞状态,正在等待某些事件发生或能够占用某些资源。处于这种状态下的进程可以被信号中断
僵死状态:子进程运行结束,父进程未退出,并且未使用wait函数等系统调用来回收子进程的退出状态。





START:进程的开始执行时间
TIME :运行时间
COMMAND:产生进程的命令 :./a.out 

优先级:
        linux系统有140个优先级:数字越小,优先级越高 
            实时进程: 0 - 99   100个
            非实时:  100- 139  40个 
            通过:ps -le查看优先级
            PRI  NI
            PRI:优先级 
            NI :谦让值(-20 ~ 19 ) 数字越小,越不谦让

 1.3 Scheduling of processes

        Process mutual exclusion:

Process mutual exclusion means that when several processes want to use a certain shared resource, at most one process is allowed to use it at any time, and other processes that want to use the resource must wait until only volunteers release the resource.

        Process synchronization:

The process of executing a group of concurrent processes in a certain order is called inter-process synchronization. A group of concurrent processes with a synchronization relationship is called a cooperative process, and the signals sent to each other by cooperative processes are called messages or events.

        Critical resources:

 In the operating system, resources that only one process is allowed to access are called critical resources.

        Critical section:

The section of program code in a process that accesses critical resources is called a critical section. In order to achieve mutually exclusive access to critical resources, it is necessary to ensure that processes enter their respective critical sections mutually.

Process scheduling:

        Preemptive and non-preemptive scheduling

Process scheduling algorithm:
        
        First come, first served scheduling algorithm
        Short process priority scheduling algorithm
        High priority priority scheduling algorithm
        time slice rotation method

2. Process API learning:

 2.1 Creation of process: 

 fork

#include <sys/types.h>
        #include <unistd.h>
        pid_t fork(void);
        功能: 
            创建子进程 
            
        参数:
            void:空 
            
        返回值: 
            创建成功: 
                父进程返回子进程的PID号 
                子进程返回0 
                
            失败: 
                返回-1,并设置错误码
    2.1.1fork() features:
1>创建出来的进程是以什么样的方式存在? 
                在fork()执行后的下面所有的代码,都会被父子进程共同执行
          
2>同一程序,多次fork,得出来的进程个数,是有规律的,参考图片 
 
3>fork以下的所有语句,都会被父子进程共同执行 如何限定操作:将父子进程的操作区分开:
 父子进程:返回值有区别,所以我们要从两者的返回值入手 
 父进程的返回值:子进程的PID号 PID号必会大于0 
    
    子进程返回值:0 
                if(pid>0){
                    //父进程的操作
                }else if(pid==0){
                    //子进程的操作 
                }else{
                    //失败操作
                }
2.1.2 Get pid
        1>如何在进程中获取PID号? 
            1>获得本身的PID号
             #include <sys/types.h>
             #include <unistd.h>
             pid_t getpid(void);
             功能: 
                    获得执行该函数的进程的PID号 
                    
             返回值: 
                    成功返回该进程的PID号 
                    失败返回-1,并设置错误码
              
            2>如何在进程中获取其父进程的PID号             
                #include <sys/types.h>
                #include <unistd.h>
                pid_t getppid(void);
             功能: 
                    获得执行该函数的进程的父进程的PID号 
                    
             返回值: 
                    成功返回该父进程的PID号 
                    失败返回-1,并设置错误码

 

2.1.3 Parent-child process relationship
父子进程之间的关系: 
    两个进程无不干扰:
     1>杀死父进程,保留子进程:功能正常运行                  
     2>保留父进程,杀死子进程:子进程会变成僵尸状态
             原因:子进程所占用系统资源并没有被释放 死了,但没完全死
                                                 
             解决:杀死父进程,让系统介入回收资源,父进程执行收尸操作,回收子进程资源

父进程的父进程为终端。
执行终端:控制终端

 2.2 Process operation replacement 

     When to use:

          (1) When the process thinks that it can no longer make any contribution to the system and users, it can call the exec function to let itself execute a new program.

          (2) If a process wants to execute another program at the same time, it can call the fork function to create a child process, and then call any exec function in the child process. This will look like a new process is spawned by executing the application

  2.2.1exec function family
exec函数族
#include <unistd.h>
   extern char **environ;//外部引入
   int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
    int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
    int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, char * const envp[] */);
    int execv(const char *path, char *const argv[]);
    int execvp(const char *file, char *const argv[]);
    int execvpe(const char *file, char *const argv[],
                       char *const envp[]);
      分析: 
        1>exec开头的:exec函数族
        2>带p的:表示根据文件名寻找要替换的程序 ,默认回去/bin  和/usr/bin 去找不带p的:表示根据路径寻找要替换的程序
        3>带l的:表示以列举的方式寻找要替换的程序
        4>带v的:表示以数组的方式寻找要替换的程序 
        5>带e的:表示以环境变量的方式传递数据,并且替换程序
   
     返回值: 
       只有发生错误时才会有返回值 
       失败返回-1,并设置错误码

    test:

        Take the last example of an execvpe function:

 char *envp[]={"hello"," world",NULL}; //The array ends with NULL, indicating that the last condition has been read

The execvpe function tells the program to jump to the new executable program. Write the contents of the array into grgv, and finally end the program.

2.2.2 Supplement: Modification of Linux environment variables:
 1>临时修改:只对当前终端有效:一次性
            export PATH=$PATH:/home/pm/shared/pro/day2_code  
            
 2>永久修改:只以用户为单位的情况下修改:针对普通用户
                1>打开用户的环境变量文件 
                    sudo vim ~/.bashrc
                    
                2>在里面添加一句话
                export PATH=$PATH:/home/pm/shared/pro/day2_code
                
                3>保存并退出 
                    source ~/.bashrc 
                    
 3>永久修改:所有用户都可以用 :针对所有
                1>执行命令: 
                    sudo vim /etc/environment 
                    
                2>在文件中添加
                :/home/pm/shared/pro/day2_code
                
                3>保存并退出

2.3 Process blocking

1>病:进程的阻塞: 
      进程互斥
进程互斥是指当有若干进程都要使用某一共享资源时,任何时候最多允许一个进程使用,其他要 使用该资源的进程必须等待,直到只用自愿者释放了该资源
      进程同步
一组并发进程按一定的顺序执行的过程称为进程间的同步。具有同步关系的一组并发进程称为合作进程,合作进程间互相发送的信号称为消息或事件。
      临界资源
操作系统中将一次只允许一个进程访问的资源称为临界资源
      临界区
进程中访问临界资源的那段程序代码称为临界区。为实现对临界资源的互斥访问,应保证诸进程互斥地进入各自的临界区。
2.3.1 Process blocking

        flock --->Lock the critical resource pointed to by the file descriptor

#include <sys/file.h>
int flock(int fd, int operation);
    功能: 
  给fd(文件描述符) 做 上锁操作 
                   
     参数: 
          fd:文件描述符 
          operation:锁的操作 
             LOCK_SH:共享锁(上锁) //可以双方同时操作
             LOCK_EX:互斥锁(上锁)
             LOCK_UN:解锁 
            LOCK_NB:不上锁
     返回值: 
           成功返回0 
           失败返回-1,并设置错误码

flock_1.c:

flock_2.c:

result:

 1.txt file content:

2.4 Exit of process

                进程有哪几种死法: 
                    1>老死     -->程序运行完毕  
                    2>被杀死   -->接收到 kill -9 信号 
                    3>自杀     -->提前遇到了return  和 exit  _exit 
                 
                自杀: 1>exit     2>_exit    3>return
                    
                1>exit --->结束进程
                #include <stdlib.h>
                void exit(int status);
                功能: 
                      结束进程  
                      
                参数: 
                      status:进程退出时的状态:进程的遗言
                      
                2>_exit --->结束进程
                #include <unistd.h>
                void _exit(int status);
                
                功能: 
                       结束进程 
                       
                参数: 
                        status:进程退出时的状态:进程的遗言
                        
                总结: 
                    exit在结束进程时,会刷新缓冲区
                    _exit直接结束进程,不会做其他任何操作
                    
                3>return 
                  return用来结束函数的 
                  但是可以通过结束main函数来达到结束进程的目的 
2.4.1 Test:

If the exit function exits normally, the subsequent program will not be executed and the buffer will be refreshed.

   

 If the _exit function exits abnormally, the subsequent program will not be executed and the buffer will not be refreshed.

 

2.5 Process corpse collection

进程的收尸: 
                收尸:释放进程运行时向系统申请的资源 
                概念:只能父进程给子进程收尸 
                1>wait
                #include <sys/types.h>
                #include <sys/wait.h>
                pid_t wait(int *wstatus);
                功能: 
                        收尸操作:带阻塞 
                        父进程阻塞等待子进程死亡,子进程死亡后做收尸操作 
                        
                参数: 
                      wstatus:接收收尸子进程的遗言 

                返回值: 
                        成功返回 被收尸子进程PID号 
                        失败返回-1,并设置错误码
                PS: 
                    wait有两套收尸逻辑: 
                        1>谁先死,收谁尸  --->优先
                        2>谁的死亡时间越接近父进程执行收尸的操作时间,收
                          谁的尸

                2>waitpid-------!!!!!!!!!!!
                #include <sys/types.h>
                #include <sys/wait.h>
                pid_t waitpid(pid_t pid, int *wstatus, int options);
                功能: 
                      给子进程收尸 --->指定收尸
                      
                参数: 
                        PID:进程号:取值范围 -----!!
                        >0: 给特定的子进程收尸(进程号为PID) 
                                例子:waitpid(12345,..,..)
                        =0:给当前进程在同一进程组内的子进程收尸
                        =-1:给任意子进程收尸,无论他在哪
                        <-1:给 进程组ID号为 |pid| 下的子进程收尸
  -12345  ---> 12345  然后收掉12345下子进程的尸                
                        wstatus:子进程的死亡状态 
                        
                        options:
                                0:代表阻塞等待收尸 
                                WNOHANG:不阻塞直接收尸 
                                
                                WUNTRACED:分析子进程的死因--->验尸   -----!!
                                    WIFEXITED:如果子进程正常死亡,则为true
                                        采用WEXITSTATUS 去获取死因
                                
                                    WIFSIGNALED:如果子进程是被信号杀死,则为true 
                                        采用WTERMSIG 去获取死因
                                         
                                    WIFSTOPPED:如果子进程是被信号暂停,则为true
                                        采用WSTOPSIG 去获取死因
               返回值: 
                    如果阻塞状态下成功返回 被收尸的子进程PID号 
                    如果不阻塞状态下:
                        成功返回 被收尸的子进程PID号
                        失败返回 0  -->没收到尸 
                    失败返回-1,并设置错误码

wait function:

Calling this function causes the process to block until either child process ends or the process receives a signal. If the process has no child processes or its child processes have ended, the wait function will return immediately.
waitpid function:
The function is similar to the wait function. You can specify how to wait for a child process to end and how to wait (blocking or non-blocking).

test:

 Program flow chart:

Multi-thread communication: http://t.csdn.cn/on1EI

Guess you like

Origin blog.csdn.net/apple_71040140/article/details/132480579