(转载)Linux进程基础

作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明。谢谢!

计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等。这些最基础的计算机动作被称为指令(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下的进程:

[email protected]:~# 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

时间: 2024-08-25 12:27:04

(转载)Linux进程基础的相关文章

Linux进程基础

Linux进程基础 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等.这些最基础的计算机动作被称为指令 (instruction).所谓的程序(program),就是这样一系列指令的所构成的集合.通过程序,我们可以让计算机完成复杂的操作.程序大多数时候被存储为可执行的文件.这样一个可执行文件就像是一个菜谱,计算机可以按照菜谱作出可口的饭

[转载] Linux进程关系

在工作中, 主进程创建了子进程, 而子进程又创建了孙子进程, 然而子进程被莫名其妙的 kill 了, 结果主进程又启动了一个子进程, 子进程又尝试创建孙子进程, 但是这时候就有问题了, 因为孙子进程还存在着, 这时候子进程就会返回失败. 如果解决这个问题, 主进程希望看到子进程非正常退出时, 杀掉所有的孙子进程. 这样就有一个问题是如何杀掉孙子进程? linux 内核早就帮我们想好了这个问题, 利用进程组. Linux的进程相互之间有一定的关系.比如说,在Linux进程基础中,我们看到,每个进程

linux 进程基础(四)

本小结主要对linux进程的调度部分进行学习总结. linux是个支持多任务的操作系统,因此才会涉及到进程的调度,调度的目的是为了让多个进程并 存.在当前CPU是多核(单核的CPU系统中面对多任务时也涉及到进程的调度)的情况下,CPU可以高效的 对处于可执行状态的进行调度处理.以提高系统的业务处理能力. 进程的调度其实质就是CPU对处于可执行状态的进程进行处理的过程,这要求linux进程调度器在设 计上可以处理几个甚至是相互矛盾的目标: A.高效性:高效意味着在相同的时间下要完成更多的任务: B

Linux 进程基础(二)

本小结主要总结,Linux下进程的几种状态及其间的相互转换. 一.Linux进程的几种状态 1.Linux进程状态:R (TASK_RUNNING),可执行状态 Linux下处于运行状态和就绪状态的进程,统称为R状态,一个进程只有处于该状态才有可能被CPU执行.同一时刻可以有多个进程处于该状态,处于这些状态的进程都将会被装入一个可执行的队列中,系统中进程调度器的作用就是从这个可执行的队列中选择一个进程进行执行. 2.Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状

linux学习之八---Linux进程基础知识

一.linux进程 linux是一个多用户多任务的操作系统. 多用户是指多个用户可以在同一时间使用计算机: 多任务是指linux可以同时执行几个任务. 进程简单来说就是运行中的程序,Linux系统的一个重要特点是可以同时启动多个进程.根据操作系统的定义:进程是操作系统资源管理的最小单位. 1.Linux进程的概念 进程是一个动态的实体,是程序一次执行过程,并且进程是操作系统资源分配的基本单位. 进程与程序的区别:进程是动态的,程序是静态的:进程是运行中的程序,而程序还是保存在硬盘上的可执行代码.

(转载)Linux进程控制——exec函数族

1.简介 在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是: #include <unistd.h> extern char **environ; int execl(const char *path, const char *arg, ...); int execlp(const char *file, const char *arg, ...); int execle(const char *path, const char *arg, ..., cha

Linux进程基础知识总结

                                    进程 进程表示一个正在运行的程序实例,它是分配资源的最小单位,这种说法特别官方. 进程是一个非常重要的东西,我们运行的系统中同时跑着N个进程,这些进程都在默默的工作着,我们编写的代码,经过编译.运行,也会生成一个进程.这个进程由程序代码.数据.变量(占用着系统内存).打开的文件(文件描述符)和环境组成.一般来说,对于Linux系统,系统会在进程之间共享程序代码和系统函数库,所以在任何时刻,内存中都只存在代码的一份副本. 由于

linux 进程基础(一)

计算机实际上所做的事情很简单,即通过对程序的调度执行,完成用户指定的一系列操作.这个过程我们可以这样在比喻,计算机是一个厨房,程序是一份菜谱.点菜的窗口就是一个输入,中间程序运行的过程就是计算机进行炒菜,而程序运行完成将结果呈现给用户的时候,就是程序运行的输出,即服务员将炒好的菜送到顾客面前. 那么进程和程序的区别又是什么呢?显然程序是存储在硬盘上的代码的集合,类似于上面比喻中的菜单,而进程就是运行的程序,其主要是运活动空间是内存.同一个程序可以被多次执行,进而形成多个进程,不同的进程可以拥有各

[转载] linux 进程管理-----pid哈希链表

为了较快的从给定的pid值得到相应的宿主结构(进程描述符)指针,内核采用了pid哈希链表结构. 首先,以下的问题要理解: 1)为什么pid哈希链表只定义2048或者4096项(根据你的内存大小确定)?直接定义为pid最大值不是最好吗? 我们都知道,查找的最快方式就是数组了,可以在常数的时间内完成查找.假如我们的pid最大值为32768,那么我们完全可以定义一个struct task_struct* name[32768];进而可以最快速的从给定的pid值中找到其相应的宿主结构.也就是指向该pid