什么是进程? 进程 = 进程相关的数据结构 + 代码和数据。
(进程相关的数据结构有很多种,由于还只知道PCB,所以在以下的说明中以PCB代替进行说明)
1. PCB即task_struct,是内核用来管理进程的进程相关数据结构的一种,本质是结构体,存储了进程的所有属性。(进程属性 != 文件属性,进程属性是描述进程的,比如优先级、进程pid等,文件属性是文件名、文件的拥有者、所属组、创建时间等。进程属性可能会包含管理进程要用到的部分文件属性。)
2. 可执行文件存储在磁盘,当可执行文件要被加载执行时,对应可执行文件的内容会被预加载到内存(一份临时拷贝)。同时,操作系统会为其创建进程PCB,PCB存储在等待列表中,所有等待CPU调度的进程的PCB放在一起,以双链表的数据结构进行存储。进程被调度的本质是CPU执行可执行程序。
3.可执行程序运行结束后,进程PCB从列表中被操作系统删除,其程序和数据也从内存中删除。
当前系统运行的所有进程的pid可以通过ls /proc/查看(如下)
如果你想要查看特定进程的进程信息,可以直接通过命令:ls /proc/想要查看的进程信息的进程pid 进行查看。
例如:查看pid = 18的进程的进程信息,如下图:
另外,大多数进程信息都可以用ps命令或top命令来获取
例如:ps aux | grep bash | grep -v grep 获取所有进程文件名含“bash”的进程的进程信息
上面对进程的介绍,频繁地提到了一个名词-----进程pid,那么,进程pid到底是什么呢?
很简单,进程pid------就是进程标识符。可以将进程pid理解成操作系统用来区分不同进程的标号,每个进程的进程pid都是不一样的,进程和进程pid是一一对应的关系。
由上,我们可以在proc目录下用进程pid来查看进程信息,那,用户怎么获取某个进程的进程pid呢?
下面介绍两个系统调用接口函数:
#include
#include
//以上是调用getpid()或getppid()需要包含的头文件
pid_t getpid(void); //获取当前进程的进程pid
pid_t getppid(void); //获取当前进程的父进程的pid
举例:
#include
#include
#include
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
return 0;
}
由可执行程序test的执行结果可知,test执行时的进程pid是17127,其父进程的pid是7564(其实就是bash进程)。
./test ,当你在命令行写入这个命令时,test(可执行文件)的文件内容就会被操作系统预加载到内存中,同时,操作系统会创建好对应的PCB。当你按下回车键的瞬间,即该进程被调度的瞬间,程序被执行(CPU调度进程等于CPU执行该程序)。
所有的进程都有父进程(除bash),即所有进程都是父进程的子进程,那,子进程是如何创建的呢?
下面介绍fork()系统调用接口函数,该函数就是用来创建进程的函数。
#include
pid_t fork(void); //创建当前进程的子进程
1.1 fork调用通过复制父进程创建子进程,子进程与父进程运行的代码和数据完全一样。但是父进程和子进程是两个独立进程(独立的进程PCB;当其中一个进程对数据进行修改时,不会影响另一个进程的数据(为什么?-----写时拷贝)。
1.2 fork创建子进程就是在内核中通过调用clone实现。clone函数的功能是创建一个PCB,fork创建进程以及以后学习的创建线程本质内部调用的clone函数实现。
fork()函数有两个返回值:返回父进程的值为创建的子进程的pid;返回子进程的是0。创建进程失败则只有一个返回值-1。
为什么fork()函数会有两个返回值(违背我们之前的认知)?
因为fork()函数的功能是创建子进程,当程序调用fork()函数时,函数返回前,子进程已创建好了,父进程的所有代码和数据都重新拷贝了一份给子进程,故,return语句也有两份,父进程的return语句的返回值是创建的子进程的pid,子进程的return语句的返回值是0,故在我们的视角,fork()函数有两个返回值。
不理解的话可以用我们平常自己写的函数进行理解:我们平常写函数,是为了完成特定的功能,比如求两数之和,那么我们问自己:return语句返回之前,两数之和是不是已经计算出来了?函数的主体功能是不是已经完成了?fork()函数的调用也是同理,返回时子进程已经创建出来了,return语句子进程也有一份,父进程和子进程的返回值不同是因为两份return语句返回了两个不同的值。
父进程和子进程分开处理。
本文主要介绍了进程有关的一些基础知识。进程相关知识的重要内容比较多,还有很多知识点,诸如进程等待、进程地址空间等都没有讲到,我会在后续的博客中进行相关内容的介绍。
码文不易,大家多多支持,有错误的地方也望大家斧正!!!