进程的定义:
“进程”是操作系统的最基本、最重要的概念之一。但迄今为止对这一概念还没有一个确切的统一的描述。下面给出几种对进程的定义描述。
进程是程序的一次执行。进程是可以并行执行的计算。进程是一个程序与其使用的数据在处理机上顺序执行时发生的活动。进程是程序在一个数据集合上的运行过程。它是系统进行资源分配和调度的一个独立单位。
进程的特征:
- 动态性:是程序的一次执行;
- 发性:进程是可以并发执行;
- 独立性:是系统进行资源分配和调度的一个独立单位;
- 异步性:进程间的相互制约,使进程执行具有间隙;
- 结构性:进程是具有结构的。
进程与程序的主要区别:
(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$ psPID TTY TIME CMD13580 pts/0 00:00:00 bash13757 pts/0 00:00:00 psfhn@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这些东西。