目录
定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)
结合实际:在Windows下的桌面,利用快捷方式打开一个exe可执行程序,就是在操作系统中创建并执行了一个进程。而在Linux下,无论是指令,如ls,pwd...还是./a.out 都是在操作系统中创建了一个进程。 有关进程的概念的理解,会随着后期学习逐渐加深。
一个小疑问:
为什么要把程序(二进制可执行程序/文件)加载到内存呢? 因为操作系统只能对进程进行管理/调度。所以,程序文件必须从磁盘load到内存变为进程之后才能被操作系统所管理。而如果没有变为进程,那么可执行程序仅仅是磁盘上的一个二进制文件。
在Windows下的任务管理器中,就可以直观的看到进程,所以说每一个在操作系统中运行的程序都是一个进程。

PCB :Process Control Block 进程控制块,作用:描述操作系统中的进程的数据结构
为了描述控制进程的运行,系统中存放进程的管理和控制信息的数据结构称为进程控制块(PCB Process Control Block),它是进程实体的一部分,是操作系统中最重要的记录性数据结构。它是进程管理和控制的最重要的数据结构,每一个进程均有一个PCB,在创建进程时,建立PCB,伴随进程运行的全过程,直到进程撤消而撤消。 - from百度百科
六个字:先描述,再组织。 这是一个管理的观念,比如我们写C++程序时,写的类就是为了描述某一个事物,而创建了类的实例化对象之后,用某一个数据结构将其组织起来,就叫做再组织。之后再使用某些算法就可以达到管理对象。 这个观念在程序开发和很多场景下都适用,而C++中的STL就是为了帮助我们更方便地组织实例化对象。
所以,在操作系统中,进程也是一个事物,操作系统要管理进程,那么最好的方法就是先描述,再组织。而描述,采用的方法就是利用一个strcut(Linux是用C写的,使用的是struct,其他操作系统未知)去存储进程的各种属性来描述进程。之后再在内存中,用数据结构将这些PCB(结构体)组织起来,来达到更好地管理进程的目的。
所以,Linux操作系统中,对进程的管理就变成了对进程PCB结构体数据结构的增删查改。
在Linux操作系统中,描述进程的PCB名为task_struct。它们的关系就像是:警察是一种职业,task_struct是一种PCB。 在Linux内核源代码中,就有task_struct的定义,是可以直接看到的。
综上,进程 = 对应的代码和数据 + 进程对应的PCB结构体
top就相当于打开了Linux下的任务管理器,通常用来查看资源占用比较高的进程。对于查看某个进程的具体数据使用ps更方便(或许是我们太菜了,不会使用top)

a. ps -axj 表示查看所有进程,第一行是对应的下面的属性的名称。
所以,当我们想要查找指定进程时,可以下面这样
b. ps -ajx | head -1 && ps -ajx | grep process_name
左边表示,打印出ps后的第一行,即属性名。右边表示ps后过滤出指定的进程。
我们在右边运行process可执行程序,左边利用ps查询出对应进程。
第二行 grep --color=auto process 是用grep工具过滤process这个进程,它在操作系统中本质上也是一个进程。

c. while :; do ps axj | head -1 && ps ajx | grep myproc | grep -v grep; sleep 1; done 循环进行ps查看进程,用于实时监控某个进程的信息。
/proc 是Linux系统下的一个目录,存储着所有进程的信息。以每个进程的PID来标识每个进程。
/proc目录是一个动态的目录,当一个进程运行结束后,在该目录内就会删除此进程的目录文件。

ls /proc/5441表示查看proc目录下名为5441目录的内容,其中存储的就是PID为5441进程的所有属性信息。

其他属性我们可能暂时不认识,但是,cwd表示当前工作目录,Current working directory。也就是这个进程所在的目录(其实就是可执行程序所在的目录) exe表示可执行程序的具体位置:/home/yzl/202283dir/process 。其他属性暂时略了。
每个进程都有一个ID,PID就类似于人的身份证号码。而PPID是该进程的父进程的PID。(在操作系统中所有进程都有父进程,所以每个进程都有PID 和 PPID )
pid_t getpid(void) get process id
pid_t getppid(void) get parent process id
这两个函数是系统调用函数,并不是C/C++库函数,其实属于是操作系统提供的库函数。 pid_t本质上是一个int


可以看到process进程的PID是9368,它的父进程的ID是32482 查找PID为32482的进程发现,他是一个名为bash的进程,其实这个bash就是Linux下的命令行解释器,我们执行指令,./运行可执行程序都是bash通过创建子进程的方式进行的。
fork是一个操作系统接口函数,作用是创建子进程。

RETURN VALUE
On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
fork函数,用于创建子进程,返回值是pid_t,如果创建子进程成功,则返回给父进程子进程的PID,返回给子进程0。如果创建子进程失败,则返回给父进程-1 ,errno被恰当地设置()
- 1 #include
- 2 #include
- 3 #include
- 4 #include
- 5
- 6 int main()
- 7 {
- 8 printf("I am parent process!\n");
- 9
- 10 pid_t ret = fork();
- 11
- 12 if(ret < 0)
- 13 {
- 14 perror("fork");
- 15 return -1;
- 16 }
- 17 else if(ret == 0)
- 18 {
- 19 // child process
- 20 // 子进程会执行这段代码
- 21 while(1)
- 22 {
- 23 printf("I am child process, fork_ret:%d, pid:%d, ppid:%d\n",ret,getpid(),getppid());
- 24 sleep(1);
- 25 }
- 26 }
- 27 else{
- 28 // parent process
- 29 // 父进程会执行这段代码
- 30 while(1)
- 31 {
- 32 printf("I am father process, fork_ret:%d, pid:%d, ppid:%d\n",ret,getpid(),getppid());
- 33 sleep(1);
- 34 }
- 35 }
- 36
- 37 return 0;
- 38 }

上方代码验证了,fork确实可以创建子进程,并且给父进程返回子进程的PID,给子进程返回0。
在fork之后,这个程序中就有了子进程,也就是由一个执行流变为了两个执行流。所以,fork之后的代码其实是两个进程共享的。那么,通过判断返回值,就可以让父子进程执行不同的代码。
在fork函数内部,主体代码肯定是创建子进程,而return的时候,子进程已经创建出来了,那么,哪个进程先执行return呢? 其实这个是不确定的。因为CPU执行一个进程的代码,是执行上若干时间,再换其他进程。只是这个若干时间非常非常小,并且速度非常块,凭人的主观意识感觉到的好像是多个进程同时执行。 所以,到底哪个进程先执行return是不确定的。这个是由操作系统的调度器决定的。
当然,创建子进程的时候,一定会在内存中创建与之对应的task_struct结构体。