多任务操做系统下一般有3个基本概念:任务、进程、线程。算法
任务:任务是一个逻辑概念,是为实现某一目的的一些列操做。一次任务可激发多个进程,这些进程相互合做来完成目标。多线程
进程:指一个具备功能的程序在某个数据集合上的一次动态执行过程,它是操做系统进行资源分配和调度的基本单元。函数
进程和程序的区别:程序是一段静态的代码,是保存在ROM上的指令和数据的集合,没有任何执行的概念;而进程是一个动态的概念,它是程序的一次执行过程,它包括了动态建立、调度、执行和消亡的整个过程。spa
线程:进程是系统中程序执行和资源分配的基本单位。操作系统
每一个进程都拥有本身的数据段、代码段、堆栈段,因此进程切换的操做对系统的开销较大。为了提升效率,操做系统引入了线程,也称为轻量级进程。.net
线程能够对进程的内存空间和资源访问,并与同一进程中的其余线程共享。所以,线程的切换开销比进程小的多。一个进程能够拥有多个线程,其中每一个线程共享该进程所拥有的资源和地址空间,所以,任何线程对系统资源的操做都会给其余的线程带来影响,因此应注意多线程中的同步。线程
那么进程到底拥有那些资源呢,系统又是怎么对进程进行资源分配和调度的呢?进程
进程的产生:系统首先在新的地址空间里建立进程、读入可执行文件、最后开始执行。系统在一开始就会初始化一个进程,叫作init(),在Linux中进程的建立依赖于函数fork(),fork()经过复制当前进程建立一个子进程,子进程与父进程的区别仅仅在于不一样的PID,PPID和某些资源及统计量。因此init进程是全部进程的上辈进程。而exec函数族则负责读取可执行文件并将其载入地址空间开始运行。内存
进程的终止:进程终止时系统必须保证进程所占用的资源回收,并通知父进程。Linux首先把终止的进程设置为僵尸状态,此时进程已没有运行。它的存在只为父进程提供信息,父进程在某个时间调用wait函数族,回收子进程的退出状态,随后子进程占用的全部资源被释放。资源
系统是如何管理和调度进程的:Linux内核将率先取得处理器的控制权,再使用调度算法将处理器分配给某个进程。
内核的调度过程:内核将全部进程存放在一个双向链表(进程链表)中,链表的每一项都是一个task_struct结构体。该结构体包含了进程的全部信息,它能完整的描述一个进程,包括进程的状态、进程的基本信息、进程的标识符、内存相关信息、父进程信息、与进程相关的终端信息、当前工做目录、打开的文件信息、所接受的信号等。
其中最为重要的是task_struct中的state(进程状态),主要包括:运行状态(TASK_RUNNING)、可中断的阻塞状态(TASK_INTERRUPTIBLE)、不可中断的阻塞状态(TASK_UNINTERRUPTIBLE)、暂停状态(TASK_STOPPED)、僵尸状态(EXIT_ZOMBLE)、消亡状态(EXIT_DEAD)。它们之间的转换关系如图:
1 进程状态转换关系图
进程所拥有的资源:Linux系统采用虚拟内存管理技术,使得每一个进程都有本身独立的地址空间。该地址空间是大小4GB的线性虚拟空间。而这4GB的进程空间又分为两部分 - 用户空间和内核空间。用户空间0-3GB,内核空间3-4GB。用户进程只有使用系统调用的时候才能访问到内核空间。每当进程切换,用户空间就会变化;而内核空间是由内核负责映射,它并不会跟着进程变化,是固定的。每一个用户进程的用户空间都是彻底独立的、互不相干的。
2 进程地址空间分布图
用户空间包括如下几个功能区域:
只读段:包含程序代码(.init .text)和只读数据(.rodata)。
数据段:存放的是全局变量和静态变量。其中可读可写数据段(.data)存放已初始化的全局变量和静态变量,BBS数据段(.bss)存放未初始化的全局变量和静态变量。
栈:有系统自动分配释放,存放函数的参数值、局部变量的值、返回地址等。
堆:存放动态分配的数据,通常有程序动态分配和释放,若程序没有释放,程序结束时由系统回收。
共享库的内存映射区域:这是Linux动态连接器和其余共享库代码映射区域。