Linux进程基础

  计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等。这些最基础的计算机动作被称为指令(instruction)。所谓的程序(program),就是这样一系列指令的所构成的集合。通过程序,我们可以让计算机完成复杂的操作。程序大多数时候被存储为可执行的文件。这样一个可执行文件就像是一个菜谱,计算机可以按照菜谱作出可口的饭菜。

  那么,程序和进程(process)的区别又是什么呢?

  进程是程序的一个具体实现。只有食谱没什么用,我们总要按照食谱的指点真正一步步实行,才能做出菜肴。进程是执行程序的过程,类似于按照食谱,真正去做菜的过程。同一个程序可以执行多次,每次都可以在内存中开辟独立的空间来装载,从而产生多个进程。不同的进程还可以拥有各自独立的IO接口。

  操作系统的一个重要功能就是为进程提供方便,比如说为进程分配内存空间,管理进程的相关信息等等,就好像是为我们准备好了一个精美的厨房。

  看一眼进程

  首先,我们可以使用$ps命令来查询正在运行的进程,比如$ps -eo pid,comm,cmd,下图为执行结果:

  (-e表示列出全部进程,-o pid,comm,cmd表示我们需要PID,COMMAND,CMD信息)

  每一行代表了一个进程。每一行又分为三列。第一列PID(process

IDentity)是一个整数,每一个进程都有一个唯一的PID来代表自己的身份,进程也可以根据PID来识别其他的进程。第二列COMMAND是这个进程的简称。第三列CMD是进程所对应的程序以及运行时所带的参数。

  (第三列有一些由中括号[]括起来的。它们是内核的一部分功能,被打扮成进程的样子以方便操作系统管理。我们不必考虑它们。)

  我们看第一行,PID为1,名字为init。这个进程是执行/bin/init这一文件(程序)生成的。当Linux启动的时候,init是系统创建的第一个进程,这一进程会一直存在,直到我们关闭计算机。这一进程有特殊的重要性,我们会不断提到它。

  如何创建一个进程

  实际上,当计算机开机的时候,内核(kernel)只建立了一个init进程。Linux内核并不提供直接建立新进程的系统调用。剩下的所有进程都是init进程通过fork机制建立的。新的进程要通过老的进程复制自身得到,这就是fork。fork是一个系统调用。进程存活于内存中。每个进程都在内存中分配有属于自己的一片空间

(address

space)。当进程fork的时候,Linux在内存中开辟出一片新的内存空间给新的进程,并将老的进程空间中的内容复制到新的空间中,此后两个进程同时运行。

  老进程成为新进程的父进程(parent process),而相应的,新进程就是老的进程的子进程(child

process)。一个进程除了有一个PID之外,还会有一个PPID(parent

PID)来存储的父进程PID。如果我们循着PPID不断向上追溯的话,总会发现其源头是init进程。所以说,所有的进程也构成一个以init为根的树状结构。

  如下,我们查询当前shell下的进程:

  root@vamei:~# ps -o pid,ppid,cmd

  PID PPID CMD

  16935 3101 sudo -i

  16939 16935 -bash

  23774 16939 ps -o pid,ppid,cmd

  我们可以看到,第二个进程bash是第一个进程sudo的子进程,而第三个进程ps是第二个进程的子进程。

  还可以用$pstree命令来显示整个进程树:

       init─┬─NetworkManager─┬─dhclient

  │ └─2*[{NetworkManager}]

  ├─accounts-daemon───{accounts-daemon}

  ├─acpid

  ├─apache2─┬─apache2

  │ └─2*[apache2───26*[{apache2}]]

  ├─at-spi-bus-laun───2*[{at-spi-bus-laun}]

  ├─atd

  ├─avahi-daemon───avahi-daemon

  ├─bluetoothd

  ├─colord───2*[{colord}]

  ├─console-kit-dae───64*[{console-kit-dae}]

  ├─cron

  ├─cupsd───2*[dbus]

  ├─2*[dbus-daemon]

  ├─dbus-launch

  ├─dconf-service───2*[{dconf-service}]

  ├─dropbox───15*[{dropbox}]

  ├─firefox───27*[{firefox}]

  ├─gconfd-2

  ├─geoclue-master

  ├─6*[getty]

  ├─gnome-keyring-d───7*[{gnome-keyring-d}]

  ├─gnome-terminal─┬─bash

  │ ├─bash───pstree

  │ ├─gnome-pty-helpe

  │ ├─sh───R───{R}

  │ └─3*[{gnome-terminal}]

  fork通常作为一个函数被调用。这个函数会有两次返回,将子进程的PID返回给父进程,0返回给子进程。实际上,子进程总可以查询自己的PPID来知道自己的父进程是谁,这样,一对父进程和子进程就可以随时查询对方。

  通常在调用fork函数之后,程序会设计一个if选择结构。当PID等于0时,说明该进程为子进程,那么让它执行某些指令,比如说使用exec库函数(library

function)读取另一个程序文件,并在当前的进程空间执行 (这实际上是我们使用fork的一大目的:

为某一程序创建进程);而当PID为一个正整数时,说明为父进程,则执行另外一些指令。由此,就可以在子进程建立之后,让它执行与父进程不同的功能。

  子进程的终结(termination)

  当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在内核里留下自己的退出信息(exit

code,如果顺利运行,为0;如果有错误或异常状况,为>0的整数)。在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用wait系统调用。这个wait函数能从内核中取出子进程的退出信息,并清空该信息在内核中所占据的空间。但是,如果父进程早于子进程终结,子进程就会成为一个孤儿(orphand)进程。孤儿进程会被过继给init进程,init进程也就成了该进程的父进程。init进程负责该子进程终结时调用wait函数。

  当然,一个糟糕的程序也完全可能造成子进程的退出信息滞留在内核中的状况(父进程不对子进程调用wait函数),这样的情况下,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。

  进程与线程(thread)

  尽管在UNIX中,进程与线程是有联系但不同的两个东西,但在Linux中,线程只是一种特殊的进程。多个线程之间可以共享内存空间和IO接口。所以,进程是Linux程序的唯一的实现方式。

  总结

  程序,进程,PID,内存空间

  子进程,父进程,PPID,fork, wait

  -------------------------------------------------------------------------------------------------------------------------------------

  下面是一些相关的视频学习资料,偏基础的资料,有需要的可以自己来看

  linux多线程编程

http://www.makeru.com.cn/course/details/1937?s=45051

  -Linux下进程和线程到底是什么

http://www.makeru.com.cn/live/3485_1457.html?s=45051

  实战Linux并发程序设计

http://www.makeru.com.cn/live/1392_951.html?s=45051

  Linux开发技巧:共享内存应用及陷阱

http://www.makeru.com.cn/live/3554_1760.html?s=45051

  linux基础

http://www.makeru.com.cn/course/details/2058?s=45051

  快速上手linux

http://www.makeru.com.cn/live/1758_310.html?s=45051

原文链接:https://www.jianshu.com/p/8b89ec343304

相关文章

  • 单片机之--上拉电阻基本知识

    1、当TTL电路驱动COMS电路时,如果TTL电路输出的高电平低于COMS电路的最低高电平(一般为3.5V),这时就需要在TTL的输出端接上拉电阻,以提高输出高...

    用户6754675
  • 循环链表及线性表的应用

    问题描述:编号为1,2,···,n的n个人围坐在一圆桌旁,每人持有一个正整数的密码。从第一个人开始报数,报到一个预先约定的正整数m时,停止报数,报m的人退席,下...

    用户6754675
  • 单片机stm32的5个时钟源的详细分析

    众所周知STM32有5个时钟源HSI、HSE、LSI、LSE、PLL,其实他只有四个,因为从上图中可以看到PLL都是由HSI或HSE提供的。

    用户6754675
  • 生产环境之“进程”两字

    一、进程概念 运行中的程序的一个副本,是被载入内存的一个指令集合 进程ID(Process ID,PID)号码被用来标记各个进程UID、GID、和SELinux...

    小小科
  • Linux并发(进程的生老病死)

    Linux中的进程有生老病死,就跟人一样,我们尤其关注其死,因为进程死后如果不处理,它会变成僵尸!

    用户2617681
  • 进程知多少?

    1 进程为什么出现?2 进程的组成3 如何竞争资源(调度算法)3.1 FCFS3.2 RR3.3 SPN3.4 SRT3.5 HRRN3.6 FB4 进程状态4...

    LieBrother
  • Linux僵尸进程

    版权声明:本文为博主原创文章,转载请注明博客地址: https://blog.csdn.ne...

    zy010101
  • 100个Linux命令(7)-进程管理

    这是100个命令的第7篇文章,主要关于进程的管理命令以及你应该知道关于进程的基本原理,相对于命令的理解,应该更加注重对于进程本身的理解。

    懒人的小脑
  • [linux] C语言Linux系统编程进程基本概念

    1.如果说文件是unix系统最重要的抽象概念,那么进程仅次于文件。进程是执行中的目标代码:活动的、生存的、运行的程序。

    陶士涵
  • Linux进程基础

    计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等。这些最基础的计算机动作被称为指令(instruction)。所谓的...

    程序员宝库

扫码关注云+社区

领取腾讯云代金券