• Linux操作系统 - 进程


    目录

    进程的定义        

    PCB

    为什么要有PCB:

    Linux下的PCB

    Linux下查看进程

    1. top(不常用)

    2. ps

    3. /proc

    PID / PPID

    Linux实例讲解

    fork

    一个思考点:


    进程的定义        

    定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)

    结合实际:在Windows下的桌面,利用快捷方式打开一个exe可执行程序,就是在操作系统中创建并执行了一个进程。而在Linux下,无论是指令,如ls,pwd...还是./a.out 都是在操作系统中创建了一个进程。  有关进程的概念的理解,会随着后期学习逐渐加深。

     一个小疑问:
    为什么要把程序(二进制可执行程序/文件)加载到内存呢? 因为操作系统只能对进程进行管理/调度。所以,程序文件必须从磁盘load到内存变为进程之后才能被操作系统所管理。而如果没有变为进程,那么可执行程序仅仅是磁盘上的一个二进制文件。

    在Windows下的任务管理器中,就可以直观的看到进程,所以说每一个在操作系统中运行的程序都是一个进程。

    PCB

    PCB :Process Control Block 进程控制块,作用:描述操作系统中的进程的数据结构

    为了描述控制进程的运行,系统中存放进程的管理和控制信息的数据结构称为进程控制块(PCB Process Control Block),它是进程实体的一部分,是操作系统中最重要的记录性数据结构。它是进程管理和控制的最重要的数据结构,每一个进程均有一个PCB,在创建进程时,建立PCB,伴随进程运行的全过程,直到进程撤消而撤消。                                                   - from百度百科

    为什么要有PCB:

    六个字:先描述,再组织。  这是一个管理的观念,比如我们写C++程序时,写的类就是为了描述某一个事物,而创建了类的实例化对象之后,用某一个数据结构将其组织起来,就叫做再组织。之后再使用某些算法就可以达到管理对象。 这个观念在程序开发和很多场景下都适用,而C++中的STL就是为了帮助我们更方便地组织实例化对象。

    所以,在操作系统中,进程也是一个事物,操作系统要管理进程,那么最好的方法就是先描述,再组织。而描述,采用的方法就是利用一个strcut(Linux是用C写的,使用的是struct,其他操作系统未知)去存储进程的各种属性来描述进程。之后再在内存中,用数据结构将这些PCB(结构体)组织起来,来达到更好地管理进程的目的。

    所以,Linux操作系统中,对进程的管理就变成了对进程PCB结构体数据结构的增删查改。

    Linux下的PCB

    在Linux操作系统中,描述进程的PCB名为task_struct。它们的关系就像是:警察是一种职业,task_struct是一种PCB。  在Linux内核源代码中,就有task_struct的定义,是可以直接看到的。

    综上,进程 = 对应的代码和数据  +  进程对应的PCB结构体

    Linux下查看进程

    1. top(不常用)

    top就相当于打开了Linux下的任务管理器,通常用来查看资源占用比较高的进程。对于查看某个进程的具体数据使用ps更方便(或许是我们太菜了,不会使用top)

    2. ps

    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查看进程,用于实时监控某个进程的信息。

    3. /proc

    /proc 是Linux系统下的一个目录,存储着所有进程的信息。以每个进程的PID来标识每个进程。

    /proc目录是一个动态的目录,当一个进程运行结束后,在该目录内就会删除此进程的目录文件。

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

     其他属性我们可能暂时不认识,但是,cwd表示当前工作目录,Current working directory。也就是这个进程所在的目录(其实就是可执行程序所在的目录)   exe表示可执行程序的具体位置:/home/yzl/202283dir/process  。其他属性暂时略了。

    PID / PPID

    每个进程都有一个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

    Linux实例讲解

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

    fork

    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. 1 #include
    2. 2 #include
    3. 3 #include
    4. 4 #include
    5. 5
    6. 6 int main()
    7. 7 {
    8. 8 printf("I am parent process!\n");
    9. 9
    10. 10 pid_t ret = fork();
    11. 11
    12. 12 if(ret < 0)
    13. 13 {
    14. 14 perror("fork");
    15. 15 return -1;
    16. 16 }
    17. 17 else if(ret == 0)
    18. 18 {
    19. 19 // child process
    20. 20 // 子进程会执行这段代码
    21. 21 while(1)
    22. 22 {
    23. 23 printf("I am child process, fork_ret:%d, pid:%d, ppid:%d\n",ret,getpid(),getppid());
    24. 24 sleep(1);
    25. 25 }
    26. 26 }
    27. 27 else{
    28. 28 // parent process
    29. 29 // 父进程会执行这段代码
    30. 30 while(1)
    31. 31 {
    32. 32 printf("I am father process, fork_ret:%d, pid:%d, ppid:%d\n",ret,getpid(),getppid());
    33. 33 sleep(1);
    34. 34 }
    35. 35 }
    36. 36
    37. 37 return 0;
    38. 38 }

     

     上方代码验证了,fork确实可以创建子进程,并且给父进程返回子进程的PID,给子进程返回0。

    在fork之后,这个程序中就有了子进程,也就是由一个执行流变为了两个执行流。所以,fork之后的代码其实是两个进程共享的。那么,通过判断返回值,就可以让父子进程执行不同的代码。

    一个思考点:

    在fork函数内部,主体代码肯定是创建子进程,而return的时候,子进程已经创建出来了,那么,哪个进程先执行return呢? 其实这个是不确定的。因为CPU执行一个进程的代码,是执行上若干时间,再换其他进程。只是这个若干时间非常非常小,并且速度非常块,凭人的主观意识感觉到的好像是多个进程同时执行。   所以,到底哪个进程先执行return是不确定的。这个是由操作系统的调度器决定的。

    当然,创建子进程的时候,一定会在内存中创建与之对应的task_struct结构体。

  • 相关阅读:
    6-10java8中关于接口的新特性
    Mali GPU“补丁缺口”让 Android 用户容易受到攻击
    Hive 中常用的函数以及数据类型
    element el-table 设置fixed导致行错乱问题
    linux vim用法
    java面试题
    Linux内核netLink套接字
    30岁年薪28W,我还是没顶住压力跳槽了····
    第九章:最新版零基础学习 PYTHON 教程—Python 元组(第二节 -从字符串和列表创建元组Python)
    有什么docker容器可以监视本地请求的码
  • 原文地址:https://blog.csdn.net/i777777777777777/article/details/126154413