【Linux】初识进程——进程概念

一、进程基本概念

什么是进程?   进程 = 进程相关的数据结构 + 代码和数据

(进程相关的数据结构有很多种,由于还只知道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都是不一样的,进程和进程pid是一一对应的关系

由上,我们可以在proc目录下用进程pid来查看进程信息,那,用户怎么获取某个进程的进程pid呢?

下面介绍两个系统调用接口函数:

#include <sys/types.h>

#include <unistd.h>

//以上是调用getpid()或getppid()需要包含的头文件

pid_t   getpid(void);  //获取当前进程的进程pid      

pid_t   getppid(void);  //获取当前进程的父进程的pid

举例:

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

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执行该程序)。

四、fork()创建进程

所有的进程都有父进程(除bash),即所有进程都是父进程的子进程,那,子进程是如何创建的呢?

下面介绍fork()系统调用接口函数,该函数就是用来创建进程的函数。

#include <unistd.h>

pid_t   fork(void);      //创建当前进程的子进程

1. fork()创建进程的原理

1.1 fork调用通过复制父进程创建子进程,子进程与父进程运行的代码和数据完全一样。但是父进程和子进程是两个独立进程(独立的进程PCB;当其中一个进程对数据进行修改时,不会影响另一个进程的数据(为什么?-----写时拷贝)。

1.2 fork创建子进程就是在内核中通过调用clone实现。clone函数的功能是创建一个PCB,fork创建进程以及以后学习的创建线程本质内部调用的clone函数实现。

2.fork()的返回值及其原理

fork()函数有两个返回值:返回父进程的值为创建的子进程的pid;返回子进程的是0。创建进程失败则只有一个返回值-1。

为什么fork()函数会有两个返回值(违背我们之前的认知)?

因为fork()函数的功能是创建子进程,当程序调用fork()函数时,函数返回前,子进程已创建好了,父进程的所有代码和数据都重新拷贝了一份给子进程,故,return语句也有两份,父进程的return语句的返回值是创建的子进程的pid,子进程的return语句的返回值是0,故在我们的视角,fork()函数有两个返回值。

不理解的话可以用我们平常自己写的函数进行理解:我们平常写函数,是为了完成特定的功能,比如求两数之和,那么我们问自己:return语句返回之前,两数之和是不是已经计算出来了?函数的主体功能是不是已经完成了?fork()函数的调用也是同理,返回时子进程已经创建出来了,return语句子进程也有一份,父进程和子进程的返回值不同是因为两份return语句返回了两个不同的值。

3.fork()调用结束后,用if语句根据返回值的不同进行分流

父进程和子进程分开处理。

五、总结

        本文主要介绍了进程有关的一些基础知识。进程相关知识的重要内容比较多,还有很多知识点,诸如进程等待、进程地址空间等都没有讲到,我会在后续的博客中进行相关内容的介绍。

        码文不易,大家多多支持,有错误的地方也望大家斧正!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值