当前位置: 首页 > article >正文

linux-多进程基础(1) 程序、进程、多道程序、并发与并行、进程相关命令,fork

程序是什么

程序是包含一系列信息的文件。这些信息描述了如何在运行时创建一个进程,包含二进制格式标识、机器语言指令、程序入口地址、数据、符号表及重定位表、共享库信息及其他信息

  1. 二进制格式标识,每个程序包含了描述可执行文件的元信息(是否可读之类的),内核利用这个信息来解释文件中给的其他信息(ELF可执行连接格式,<-知道就行)
  2. 机器语言指令:对程序进行编码
  3. 程序入口地址:main()
  4. 数据:程序中的初始变量值和字面量值,例如字符串什么的
  5. 符号表及重定位表:描述程序中函数和变量的位置及名称。这些表格有很多用途,例如调试和运行时的符号解析(动态链接)
  6. 共享库和动态链接信息:就是共享库的有关信息,这部分不在代码里,要到内存里去找
  7. 其他信息:

字面量值:就出现了的都属于那种字面量,就露面了的。int a = 10这个就是

进程是什么

简而言之:进程是正在运行的程序的实例,是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是分配单元也是执行单元。进程也是由内核定义的抽象实体(存在,也不存在)。
程序与进程的关系:一个程序可以用来创建多个进程。程序是一个文件,占用磁盘的空间,进程运行的时候,内核会分配CPU和内存给进程当作资源。
从内核的角度看,进程是由用户内存空间和一些内核数据结构组成。

  • 用户内存空间:包括一些代码、变量
  • 内核数据结构:维护进程状态的信息,这些信息包含与进程相关的标识号、虚拟内存表、文件描述符表、信号传递及处理有关信息等信息。

在这里插入图片描述

关于多道程序设计

首先单道程序,即再计算机内存中只允许一个的程序运行
而多道程序设计为:在内存中存放多个相互独立的程序,使他们在管理程序之下,能够相互穿插运行,多道程序同时处于开始和结束的状态,可以提高CPU的利用率
对于一个单CPU来说,同时运行多个程序是宏观的状态,在微观时间范围下,一个CPU上的运行的程序只有一个。
CPU一秒能运行10亿条指令,所以看似同时运行

时间片

又称为“量子”或者“处理器片”,是操作系统分配给每个正在运行的进程微观上的一段CPU时间。时间片通常很短,在5ms-800ms
时间调度策略:(可以之后再补充)

  • 时间片由内核的调度程序分配给每个进程。首先内核给每个进程分配相等的时间片,如何没进程轮番执行相应的时间,当所有时间片都处于耗尽状态,内核再重新为进程分配时间片,如此往复。

并发与并行

并行(parallel):指同一时刻有多条指令多个处理器上同时执行
并发(concurrency):指同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得宏观上有多个进程同时执行的效果(PS:就像CPU的多道程序设计)
在这里插入图片描述

PCB进程控制块

这个就是虚拟地址空间的内核数据里面的进程管理里面的,是一个task_struct结构体。它包含以下内部成员:(就回想哪些跟进程有关的)

  • 进程ID
  • 进程的状态:有就绪、运行、挂起、停止
  • 进程切换时需要保存和恢复的一些CPU寄存器
  • 描述虚拟地址空间的信息
  • 描述控制终端的信息,就每个进程有个对应的终端
  • 当前工作目录
  • umask掩码
  • 文件描述符表
  • 和信号相关的信息
  • 用户id和组id
  • 会话(session)和进程组
  • 进程可以使用的资源上限

进程的状态(面试会问到)

三态模型:进程状态分为三个基本状态:就绪态、运行态,阻塞态
三态进程转换图
五态模型:新建态、就绪态、运行态,阻塞态、终止态
在这里插入图片描述

进程相关命令

ps aux / ajx
	-a:显示终端上所有进程,包括其他用户的进程
	-u:显示进程的详细信息
	-x:显示没有控制终端的进程
	-j:列出与作业控制相关的信息
top
实时显示进程动态,可以在使用top 加上-d来指定更新信息的时间间隔, 在top执行之后,可以输入以下案件对结果排序和筛选
	-M 根据内存使用量排序
	-P 根据CPU占有率排序
	-T 根据进程运行时间长短排序
	-U 根据用户名来筛选进程
	-K 输入指定的PID杀死进程

kill [-signal] pid
kill -l:列出所有信号
kill -9 进程ID等价于kill –SIGKILL 进程ID
killall name:根据进程名杀死进程

进程号和相关函数

  • 每个进程都由进程号来标识,其类型为 pid_t(整型),进程号的范围:0~32767。进程号总是唯一的,但可以重用。当一个进程终止后,其进程号就可以再次使用
  • 任何进程(除 init 进程)都是由另一个进程创建,该进程称为被创建进程的父进程,对应的进程号称为父进程号(PPID)
  • 进程组是一个或多个进程的集合。他们之间相互关联,进程组可以接收同一终端的各种信号,关联的进程有一个进程组号(PGID)。默认情况下,当前的进程号会当做当前的进程组号
  • 进程号和进程组相关函数
    • pid_t getpid(void);:获取进程ID
    • pid_t getppid(void);:获取进程的父进程ID
    • pid_t getpgid(pid_t pid);:获取进程的组ID

进程创建

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

    pid_t fork(void);
        函数的作用:用于创建子进程。
        返回值:
            fork()的返回值会返回两次。一次是在父进程中,一次是在子进程中。(即,在父进程中返回子进程ID,在子进程中返回0)
            如何区分父进程和子进程:通过fork的返回值。
            在父进程中返回-1,表示创建子进程失败,并且设置errno

eg:

    int num = 10;
    // 创建子进程
    pid_t pid = fork();

    // 利用返回的pid判断是父进程还是子进程,执行对应的代码
    if(pid > 0) {
        printf("pid : %d\n", pid);
        // 如果大于0,返回的是创建的子进程的进程号,当前是父进程
        printf("i am parent process, pid : %d, ppid : %d\n", getpid(), getppid());
        printf("parent num : %d\n", num);
        num += 10;
        printf("parent num += 10 : %d\n", num);
    } else if(pid == 0) {
        // 当前是子进程
        printf("i am child process, pid : %d, ppid : %d\n", getpid(),getppid());
        printf("child num : %d\n", num);
        num += 100;
        printf("child num += 100 : %d\n", num);
    }
    /*西面是父进程和子进程共享的代码,会交替运行*/
    // for循环
    for(int i = 0; i < 3; i++) {
        printf("i : %d , pid : %d\n", i , getpid());
        sleep(1);
    }

那么得到的结果会是:
在这里插入图片描述

  1. 父进程的代码和子进程是一样的
  2. 两个进程的变量及其值是互不相干的(num没有变)

fork的原理(面试会问到)

  • Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。写时拷贝是一种可以推迟甚至避免拷贝数据的技术

  • 内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间,只有在需要写入的时候才会复制地址空间,从而使各个进程拥有各自的地址空间。即资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享(示例程序中num的作用)

  • fork之后父子进程共享文件。fork产生的子进程与父进程有相同的文件描述符,指向相同的文件表,引用计数增加,共享文件偏移指针

*真拷贝了,用户数据都会拷贝,内核数据也会拷贝只是pid也就是进程ID变了

父子进程关系

区别

  • fork()函数的返回值不同。父进程中: >0 返回的是子进程的ID,子进程中: =0
  • pcb中的一些数据不同。pcb中存的是当前进程的ID(pid)当前进程的父ID(ppid)信号集

共同点

  • 在某些状态下,即子进程刚被创建出来,还没有执行任何的写数据的操作。此时用户区的数据文件描述符表父进程和子进程一样

父子进程对变量共享说明

  • 刚开始的时候,是一样的,共享的。如果修改了数据,不共享了
  • 读时共享(子进程被创建,两个进程没有做任何的写的操作),写时拷贝

http://www.kler.cn/a/560000.html

相关文章:

  • 瑞幸咖啡×动漫IP:精选联名案例,解锁品牌营销新玩法
  • Python生成器2-250224
  • unity学习52:UI的最基础组件 rect transform,锚点anchor,支点/轴心点 pivot
  • 如何生成traceid以及可视化展示
  • 蓝桥杯 3.搜索
  • Spring Core面试题
  • MySQL数据库连接池泄露导致MySQL Server超时关闭连接
  • 硬件加速与技术创新双轮驱动:DeepSeek和ChatGPT性能进阶的未来蓝图
  • 51单片机-AT24CXX存储器工作原理
  • 深入解析 Linux 文件系统:EXT4、NTFS、NFS、CIFS 等的特点与应用(中英双语)
  • QML 将CheckBox添加到一个组,同一时间只能勾选一个,具有排他性
  • 接雨水的算法
  • 盲视观测者效应:认知的量子诗学 AI回复盲人双缝实验
  • 便携式动平衡仪Qt应用层详细设计方案(基于Qt Widgets)
  • 华为2025年技术发布会:智能汽车核心技术大爆发
  • 连接数据库的方式
  • 【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter22-处理 XML
  • Lecture 2 - Python
  • Apache Tomcat RCE 稳定复现 保姆级!(CVE-2024-50379)附视频+POC
  • JavaWeb-Servlet对象生命周期