进程基本概念

基本概念

  • 程序:程序是静止的,是磁盘上的一个文件。

  • 课本知识:程序的一个执行实例,正在执行的程序等(动态的)。

  • 内核观点:担当分配系统资源(CPU时间、内存)的实体。

  • 程序一旦被操作系统加载到内存中,那么程序就变成了进程。

  • 进程信息放在一个叫进程控制块(PCB)的数据结构中,可以理解为进程属性的集合。

  • Linux中描述进程的结构体叫做task_struct。

  • task_struct是Linux内核的一种数据结构,会被装载到RAM(内存)里并且包含着进程的信息

 在进程执行时,任意给定一个时间,进程都可以唯一的被表征为以下元素:

  • 标识符:跟这个进程相关的唯一标识符,用来区分其他进程。

  • 状态:如果进程正在执行,那么进程处于运行状态。

  • 优先级:相对于其他进程的优先级。

  • 程序计数器:程序中即将被执行的下一条指令的地址。

  • 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享内存块的指针。

  • 上下文数据:程序执行时处理器的寄存器中的数据。

  • I/O状态信息:包括显示的I/O请求、分配给进程的I/O设备和被进程使用的文件列表。

  • 记帐信息:可能包括处理器时间总和、使用的时钟数总和、时间限制、记账号等。

  因此,可以说进程是由程序代码和相关数据还有进程控制块组成。对于一个单处理器计算机,在任何时间最多只有一个进程在运行,正在运行的这个进程状态为运行态。

进程的创建和终止

  • 进程的创建:
      当一个新进程添加到那些正在被管理的进程集合中去时,操作系统需要建立用于管理该进程的数据结构,并在内存中给它分配地址空间,这些行为构成了一个新进程的创建过程。通常会有以下4个事件导致创建一个新进程:

描述

  • 进程的终止:
      任何一个计算机都必须为进程提供表示其完成的方法,批量处理作业中应该包含一个Halt指令或用于终止操作系统显示服务调用来终止。在前一种情况下,Halt指令将产生一个中断,警告操作系统一个进程已经完成。对交互式应用程序,用户的行为将指出何时进程完成。在有些操作系统中,进程可以被创建它的进程终止,或当父进程终止而终止。以下是进程终止的几种情况:

描述

查看进程

描述

  • PID:pid_t getpid(void);得到进程的PID
    PID是程序被操作系统加载到内存成为进程后动态分配的资源。
    每次程序执行的时候,操作系统都会重新加载,PID在每次加载的时候都是不同的。

  • PPID:pid_t getppid(void);得到进程的PPID
    PPID是程序的父进程号。

  • 一个进程创建的另一个新进程称为子进程。相反地,创建子进程的进程称为父进程。对于一个普通的用户进程,它的父进程就是执行它的那个Shell,对于Linux而言,Shell就是bash。

  • 所有进程的祖先为init进程。

创建一个进程:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int mian(){
    while(1){
        sleep(1);
    }
    return 0;
}

描述

通过系统调用获取进程标识符

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int mian(){
    pid_t pid = getpid();
    printf("pid:%d\n",pid);
    pid_t ppid = getppid();
    printf("ppid:%d\n",ppid);
    while(1){
        sleep(1);
    }
    return 0;
}

描述

ps axj | grep ./a.out 

描述

通过系统调用创建进程

fork特点:

  1. 一次调用有两个返回值,父进程返回子进程PID,子进程返回0。

  2. 父进程和子进程都从fork执行结束后的位置继续执行。

  3. 子进程以父进程为模板(PCB,数据和代码)。写时拷贝

  4. 父子进程执行的先后顺序不确定,取决于操作系统调度器。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int mian(){
    int ret = fork();
    printf("pid: %d, ppid: %d, ret: %d\n", getpid(), getppid(), ret);
    while(1){
        sleep(1);
    }
    return 0;
}

描述

使用if进行分流:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int mian(){
    int ret = fork();
    if(ret < 0){
        perror("fork");
        return 1;
    }
    else if(ret == 0){
        printf("I am child: pid: %d, ppid: %d, ret: %d\n", getpid(), getppid(), ret);
    }
    else{
        printf("I am father: pid: %d, ppid: %d, ret: %d\n", getpid(), getppid(), ret);
    }
    while(1){
        sleep(1);
    }
    return 0;
}

描述

进程状态

描述

  • R(就绪):表明进程要么在运行中,要么在运行队列中

  • S(挂起):进程在等待事件完成(可中断睡眠)

  • D(深度睡眠):进程通常会等待I/O结束(不可中断睡眠)

  • T(暂停):可以通过发送SIGSTOP信号停止进程。这个被暂停的进程可以通过发送SIGCONT信号让进程继续运行。

  • t(跟踪)

  • X(死亡):只是一个返回状态。

  • z(僵尸状态):它的父进程尚未调用wait函数

描述

停止9037号进程:

描述

恢复:

描述

僵尸进程

  • 当子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。

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

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>

int main(){
    int ret = fork();
    if(ret < 0){
        perror("fork");
        return 1;
    }
    else if(ret > 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;
}

描述

描述

僵尸进程会占用系统资源,如果很多,则会严重影响服务器的性能
若一直不回收,有可能造成内存泄漏

孤儿进程

  • 一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int mian(){
    int ret = fork();
    if(ret < 0){
        perror("fork");
        return 1;
    }
    else if(ret == 0){
        printf("I am child: pid: %d, ppid: %d, ret: %d\n", getpid(), getppid(), ret);
        sleep(10);
    }
    else{
        printf("I am father: pid: %d, ppid: %d, ret: %d\n", getpid(), getppid(), ret);
        sleep(3);
        exit(0);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/adorable_/article/details/80035032