Linux - Process Introduction

1. Process

1. Basic Concepts

    Textbook concepts: an execution instance of a program, the program being executed, etc.

     Kernel point of view: the entity responsible for allocating system resources

Description Process - PCB

   Process information is placed in a data structure called a process control block, which can be understood as a collection of process attributes

    The reason why it is called PCB (process control block) in textbooks, PCB under Linux operating system is task_struct

task_struct - a type of PCB (a data structure of the Linux kernel, which is loaded into RAM (memory) and contains process information)

task_struct content classification

    Identifier: a unique identifier that describes this process and is used to distinguish other processes

    Status: task status, exit code, exit message, etc.

    priority: priority relative to other processes

    Program Counter: The address of the next instruction to be executed in the program

    Memory pointers: pointers containing program code and process-related data, as well as pointers to memory blocks shared with other processes

    Context data: the data in the processor's registers when the process is executing

    I/O status information: including displayed I/O requests, I/O devices allocated to the process, and a list of files used by the process

    Accounting information: may include total processor time, total number of clocks used, time limit, account number, etc.

    other information

2. Organizational Process

     It can be found in the kernel source code, all processes running in the system are stored in the kernel in the form of a task_struct linked list

3. View the process

    Process information can be viewed through the /proc system folder

    To get process information with PID 1, you need to view the /proc/1 folder:



Get process identifier via system call

    The system assigns a unique identification number to each process, and this identification number is called the process ID (process identifer).

    Process id (PID)

    Parent process id (PPID)

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    intmain()
    {
        printf("pid:%d\n",getpid());
        printf("ppid:%d\n",getppid());
        return 0;
    }

4. Create a process through a system call - fork() first understanding

The general process of process creation:

   1. Assign PID

    2. Assign the PCB

    3. Copy the parent process environment

    4. Copy the contents of the parent process address space to its own address space

    5. Put into the ready queue

    Use the man manual to know fork():


    return value:


    Parent-child process code sharing, data space is opened up separately

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    intmain()
    {
        int ret = fork ();
        printf("hello proc:%d,ret:%d\n",getpid(),ret);
        return 0;
    }

    After fork(), you usually use if to shunt:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    intmain()
    {
        int ret = fork ();
        if(ret<0){
            perror("fork");
            return 1;
        }
        else if(ret==0){  //child
            printf("I am child:%d,ret:%d\n",getpid(),ret);
        }
        else{   //father
            printf("I am father:%d,ret:%d\n",getppid(),ret);
        }
        sleep(2);
        return 0;
    }

2. Procedures and Processes

    程序:完成特定任务的一系列指令集合

    进程:从用户角度看,进程是程序的一次动态执行过程;从操作系统角度看,进程是操作系统分配资源的基本单位,也是最小单位

   每个进程都有自己的状态和独立的地址空间

    进程需要有相关的数据结构来管理,操作系统通过PCB感知一个进程的存在

    程序:数据+代码

    进程:数据+代码+堆栈+PCB

进程和程序的区别:

    进程是动态,程序是静态

    进程的生命周期短暂,程序永久

    进程有重要的数据结构PCB

    一个进程只能对应一个程序,一个程序可以对应多个进程

三、进程状态


1.进程的几种状态

    R 运行状态(running):并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里

    S 睡眠状态(sleeping):意味着进程在等待事件完成(也可叫做可中断睡眠 interruptible sleep)

   D 磁盘休眠状态(Disk sleep):有时也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待 I/O的结束

    T 停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止(T)进程,这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行

    X 死亡状态(dead):这个状态只是一种返回状态,你不会在任务列表里看到这个状态


2.进程状态的修改

    通过kill演示一下T、R状态:

    · kill -l:查看系统支持的信号列表

    · ps -l:查看进程信息

    · kill -SIGSTOP pid:将该进程状态改为T状态

    · kill -SIGCONT pid:将该进程状态改为R状态


Z(zombie)僵尸进程

    · 僵尸状态(zombie)是一个比较特殊的状态,当进程退出并且父进程(使用wait()系统调用)没有读到子进程退出的返回代码时就会产生僵尸进程

    · 僵尸进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态码

    · 所以,只要子进程退出父进程还在运行,但父进程中没有读取子进程状态,子进程进入Z状态

举例:维持30秒僵尸进程

    #include <stdio.h>
    #include <stdlib.h>
    
    int main()
    {
        pid_t id=fork();
        if(id<0){
            perror("fork");
            return 1;
        }
        else if(id>0){
            printf("parent [%d] is sleeping...\n",getpid());
            sleep(30);
        }
        else{
            printf("child [%d] is begin z...\n",getpid());
            sleep(5);
            exit(EXIT_SUCCESS);
        }
        return 0;
    }
    


编译运行并在另一个终端下启动监控:



测试结果:


可以看到子进程5秒后由S状态进入僵尸状态

僵尸进程危害

    · 进程的退出状态必须被维持下去,父进程若一直不读取,子进程将一直处于Z状态

    · 维护退出状态本身就是要用数据维护,也属于进程的基本信息,所以保存在PCB中,即Z状态一直不退出,PCB一直都要维护

    · 若一个父进程创建了很多子进程,就是不回收,就会造成资源的浪费,因为数据结构本身就要占用内存,就像C语言中定义一个结构体变量,是要在内存的某个位置开辟空间

    · 造成内存泄露

孤儿进程

    父进程如果提前退出,那么子进程后退出,进入Z状态之后,该如何处理?

    父进程先退出,子进程就被称为孤儿进程

    孤儿进程被1号init进程“领养”(当然要有init进程回收)

举例:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main()
    {
        pid_t id=fork();
        if(id<0){
            perror("fork");
            return 1;
        }
        else if(id==0){
            printf("I am child,pid:%d\n",getpid());
            sleep(10);
        }
        else{
            printf("I am father,pid:%d\n",getpid());
            sleep(3);
            exit(0);
        }
        return 0;
    }

测试结果:







Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326974306&siteId=291194637