进程相关概念、C程序的空间分配

进程的定义:
“进程”是操作系统的最基本、最重要的概念之一。但迄今为止对这一概念还没有一个确切的统一的描述。下面给出几种对进程的定义描述。
进程是程序的一次执行。进程是可以并行执行的计算。进程是一个程序与其使用的数据在处理机上顺序执行时发生的活动。进程是程序在一个数据集合上的运行过程。它是系统进行资源分配和调度的一个独立单位。
进程的特征:

  • 动态性:是程序的一次执行;
  • 发性:进程是可以并发执行;
  • 独立性:是系统进行资源分配和调度的一个独立单位;
  • 异步性:进程间的相互制约,使进程执行具有间隙;
  • 结构性:进程是具有结构的。

进程与程序的主要区别:
(1)程序是永存的;进程是暂时的,是程序在数据集上的一次执行,有创建有撤销,存在是暂时的;

(2)程序是静态的观念,进程是动态的观念;

(3)进程具有并发性,而程序没有;

(4)进程是竞争计算机资源的基本单位,程序不是。

(5)进程和程序不是一一对应的: 一个程序可对应多个进程即多个进程可执行同一程序; 一个进程可以执行一个或几个程序。

进程概念和程序概念最大的不同之处在于:

(1)进程是动态的,而程序是静态的。

(2)进程有一定的生命期,而程序是指令的集合,本身无“运动”的含义。没有建立进程的程序不能作为1个独立单位得到操作系统的认可。

(3)1个程序可以对应多个进程,但1个进程只能对应1个程序。进程和程序的关系犹如演出和剧本的关系。

如何查看系统中有哪些进程:

使用ps指令查看,在实际工作中,配合grep来查找程序中是否存在某一个进程。

ps命令:

ps命令用于查看系统中的进程状态,格式为“ps [参数]”。

ps命令的参数以及作用:

参数作用
-a显示所有进程(包括其他用户的进程)
-u用户以及其他详细信息
-x显示没有控制终端的进程

Linux系统中时刻运行着许多进程,如果能够合理地管理它们,则可以优化系统的性能。在Linux系统中,有5种常见的进程状态,分别为运行、中断、不可中断、僵死与停止,其各自含义如下所示。
R(运行):进程正在运行或在运行队列中等待。

S(中断):进程处于休眠中,当某个条件形成后或者接收到信号时,则脱离该   状态。

D(不可中断):进程不响应系统异步信号,即便用kill命令也不能将其中断。

Z(僵死):进程已经终止,但进程描述符依然存在, 直到父进程调用wait4()系统函数后将进程释放。

T(停止):进程收到停止信号后停止运行。

当执行ps aux命令后通常会看到如表2-7所示的进程状态,表2-7中只是列举了部分输出值,而且正常的输出值中不包括中文注释。
在这里插入图片描述top命令:
top命令用于动态地监视进程活动与系统负载等信息,其格式为top。

top命令相当强大,能够动态地查看系统运维状态,完全将它看作Linux中的“强化版的Windows任务管理器”。

ps -aux|grep 加所要查找的进程相关信息

其中|相当于管道,grep相当于滤网,信息从管道流下经过滤网查找自己想要的信息。

以下是使用ps查看进程:
fhn@ubuntu:~/jincheng$ ps
   PID TTY          TIME CMD
 13580 pts/0    00:00:00 bash
 13757 pts/0    00:00:00 ps


fhn@ubuntu:~/jincheng$ ps -aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.3 225324  6108 ?        Ss   Jun27   0:30 /sbin/init auto noprompt
root          2  0.0  0.0      0     0 ?        S    Jun27   0:00 [kthreadd]
root          3  0.0  0.0      0     0 ?        I<   Jun27   0:00 [rcu_gp]
root          4  0.0  0.0      0     0 ?        I<   Jun27   0:00 [rcu_par_gp]
root          6  0.0  0.0      0     0 ?        I<   Jun27   0:00 [kworker/0:0H-kb]
root          9  0.0  0.0      0     0 ?        I<   Jun27   0:00 [mm_percpu_wq]
root         10  0.0  0.0      0     0 ?        S    Jun27   0:01 [ksoftirqd/0]
root         11  0.0  0.0      0     0 ?        I    Jun27   1:17 [rcu_sched]
root         12  0.0  0.0      0     0 ?        S    Jun27   0:01 [migration/0]
root         13  0.0  0.0      0     0 ?        S    Jun27   0:00 [idle_inject/0]
root         14  0.0  0.0      0     0 ?        S    Jun27   0:00 [cpuhp/0]
root         15  0.0  0.0      0     0 ?        S    Jun27   0:00 [cpuhp/1]
root         16  0.0  0.0      0     0 ?        S    Jun27   0:00 [idle_inject/1]
root         17  0.0  0.0      0     0 ?        S    Jun27   0:01 [migration/1]
root         18  0.0  0.0      0     0 ?        S    Jun27   0:00 [ksoftirqd/1]
root         20  0.0  0.0      0     0 ?        I<   Jun27   0:00 [kworker/1:0H-kb]
root         21  0.0  0.0      0     0 ?        S    Jun27   0:00 [cpuhp/2]
root         22  0.0  0.0      0     0 ?        S    Jun27   0:00 [idle_inject/2]
root         23  0.0  0.0      0     0 ?        S    Jun27   0:01 [migration/2]
root         24  0.0  0.0      0     0 ?        S    Jun27   0:00 [ksoftirqd/2]
root         26  0.0  0.0      0     0 ?        I<   Jun27   0:00 [kworker/2:0H-kb]
root         27  0.0  0.0      0     0 ?        S    Jun27   0:00 [cpuhp/3]
root         28  0.0  0.0      0     0 ?        S    Jun27   0:00 [idle_inject/3]

什么是进程标识符:
系统给每个进程定义了一个唯一标识该进程的非负正数,称作进程标识符。进程标识符可以简单的表示为主进程表中的一个索引。当某一进程终止后,其标识符可以重新用作另一进程的标识符。不过,在任何时刻,一个标识符所代表的进程是唯一的。系统把标识符 0 和 1 保留给系统的两个重要进程。进程 0 是调度进程,它按一定的原则把处理机分配给进程使用。进程 1 是初始化进程,它是程序/sbin/init 的执行。进程 1 是 UNIX 系统那其它进程的祖先,并且是进程结构的最终控制者。

进程属性-标识符:
每个进程都有6个重要的ID:进程ID、父进程ID、有效用户ID、有效组ID、实际用户ID和实际组ID。这6个标识符保存在进程的PCB中。

#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void); //返回值:调⽤进程的进程ID
pid_t getppid(void); //返回值:调⽤进程的⽗进程ID
uid_t getuid(void); //返回值:调⽤进程的实际⽤户ID
uid_t geteuid(void); //返回值:调⽤进程的有效⽤户ID
gid_t getgid(void); //返回值:调⽤进程的实际组ID
gid_t getegid(void); //返回值:调⽤进程的有效组ID


返回值:pid_t类型
pid_t定义的类型都是进程号类型

pid_t是一个typedef定义类型。

用它来表示进程id类型。

sys/types.h:
typedef short           pid_t;       /* used for process ids */

pid_t就是一个short类型变量,实际表示的是内核中的进程表的索引

头文件里也不过是个typedef而已.
使用pid_t而不使用int只是为了可移植性好一些.
因为在不同的平台上有可能
typedef int pid_t
也有可能
typedef long pid_t

什么叫父进程和子进程:

  • 父进程:指已创建一个或多个子进程的进程。在UNIX里,除了进程0以外的所有进程都是由其他进程使用系统调用fork创建的,这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程0以外的进程都只有一个父进程,但一个进程可以有多个子进程。
  • 子进程:指的是由另一进程(对应称之为父进程)所创建的进程。子进程继承了对应的父进程的大部分属性,如文件描述符。在Unix中,子进程通常为系统调用fork的产物。在此情况下,子进程一开始就是父进程的副本,而在这之后,根据具体需要,子进程可以借助exec调用来链式加载另一程序。

C程序的存储空间是如何分配的?

大佬博客:堆和栈详解

程序运行时的内存分区主要分为BSS段、数据段、代码段、堆、栈

  • BSS段:Block Started by Symbol,一般是指存放程序中未初始化的全局变量的一块内存区域。BSS段属于静态内存分配。
  • 数据段:data segment,一般是指用来存放程序中已初始化的全局变量的一块内存区域。 static 意味着 在数据段中 存放变量,数据段属于静态内存分配。
  • 代码段:code segment/text segment,通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些 只读的常数变量 ,例如字符串常量等。程序段为程序代码在内存中的映射。一个程序可以在内存中有多个副本。
  • 堆:heap,堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc/free等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)/释放的内存从堆中被剔除(堆被缩减)。
  • 栈:stack,栈又称堆栈,存放程序的局部变量(但不包括static声明的变量, static 意味着 在数据段中 存放变量)。除此以外,在函数被调用时,栈用来传递参数和返回值。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。储动态内存分配,需要程序员手工分配,手工释放。

在这里插入图片描述
如上图所示:红色箭头指向的是代码段,粉色箭头指向的在函数外被初始化过的变量,我们叫做数据段(main函数里面初始化的变量属于局部变量,其生命周期和全局变量一样,所以上方图片int a=0属于数据段图片有点错误),黄色箭头指向的在函数外没有被初始化的变量(BSS段),自己编写好的C代码编译后会生成一个可执行文件,当我们运行这个可执行文件是操作系统会给程序划分一段内存空间,这段内存空间就相当于左边那副黄色的图所示,从高地址到低地址会把代码文件里面的代码段载入到对应的地址,其中malloc申请的空间是在堆上面,栈存放的内容是:函数调用返回的地址、相关参数、函数里面的局部变量和寄存器内容等。自动变量(也就是局部变量)以及每次函数调用所需要的保存的信息都存放在此段中,每次函数调用时,其返回地址以及调用者的环境信息(例如某些机器寄存器的值)都存放在栈中。然后最近被调用的函数在栈上为其自动和临时变量分配存储空间,通过这种方式使用栈可以递归调用C函数,递归函数每次调用自身时,就使用一个新的栈帧,因此函数调用实例中的变量不会影响到另一个函数调用实例中的变量。左图中:最上面是命令行和环境变量也就是argc和argv这些东西。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的问题是如何用高级语言编写和调试一个内存连续分配中动态分区分配模拟程序,以加深对进程概念进程调度算法的理解。 首先,我们需要了解动态分区分配的基本原理。动态分区分配是指在内存中按需分配一定大小的空间进程使用。当一个进程需要内存空间时,系统会在空闲内存区域中寻找一块大小足够的空间分配给该进程。当该进程释放内存空间时,系统会将该空间标记为空闲状态,以便后续进程使用。 接下来,我们可以使用高级语言(例如C语言)来实现模拟程序。具体实现步骤如下: 1. 定义内存块结构体(MemoryBlock)来表示内存中的一个连续区域,包括起始地址、结束地址、大小和是否被占用等属性; 2. 定义进程结构体(Process)来表示一个进程,包括进程ID、所需内存大小和已分配内存块等属性; 3. 定义一个动态分区分配函数(allocateMemoryBlock),该函数接受一个进程结构体作为参数,根据进程所需内存大小寻找内存中合适的连续区域,并将该区域分配给该进程; 4. 定义一个内存释放函数(freeMemoryBlock),该函数接受一个进程结构体作为参数,将该进程所占用的内存块标记为空闲状态; 5. 在主函数中模拟多个进程的内存分配和释放过程,输出每个进程的内存分配情况和当前内存状态。 在实现过程中,我们可以使用链表或数组等数据结构来管理内存块和进程,以便更方便地进行内存分配和释放操作。 完成实现后,我们可以通过调试程序来测试其正确性和可靠性,并加深对进程概念进程调度算法的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值