进程就是处于执行期的程序(目标码存放在某种存储介质上)。但进程并不只仅局限于一段可执行程序代码( Unix称其为代码段,text section)。一般进程还要包含其余资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具备内存映射的内存地址空间及一个或多个执行线程(threa do fexecution),固然还包括用来存放全局变量的数据段等。linux
程序自己并非进程,进程是处于执行期的程序以及相关的资源的总称。实际上,彻底可能存在两个或多个不一样的进程执行的是同一个程序。而且两个或两个以上并存的进程还能够共享许多诸如打开的文件、地址空间之类的资源。编程
一般,建立新的进程都是为了当即执行新的、不一样的程序,而接着调用exec。这组函数就能够建立新的地址空间,并把新的程序载入其中。数组
最终,程序经过exi的系统调用退出执行。这个函数会终结进程并将其占用的资源释放掉。父进程能够经过wait4()9系统调用查询子进程是否终结,这其实使得进程拥有了等待特定进程执行完毕的能力。进程退出执行后被设置为僵死状态,直到它的父进程调用wait()或waitpid()为止。并发
进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其余更多信息(见下图)
函数
每一个任务的thread_info 结构在色的内核栓的尾端分配。结构中task 域中存放的是指向该任务实际task_struct 的指针。spa
Unix 的进程建立很特别。许多其余的操做系统都提供了产生(spawn)进程的机制,首先在新的地址空间里建立进程,读入可执行文件,最后开始执行。Unix 采用了不同凡响的实现方式,它把上述步骤分解到两个单独的函数中去执行: forkO 和exec()首先,fork()经过拷贝当前进程建立一个子进程。子进程与父进程的区别仅仅在于PID(每一个进程惟一)、PPID(父进程的进程号,子进程将其设置为被拷贝进程的PID)和某些资源和统计量(例如,挂起的信号,它没有必要被继承〉。exec()函数负责读取可执行文件并将其载入地址空间开始运行。把这两个函数组合起来使用的效果跟其余系统使用的单一函数的效果类似。操作系统
Linux 的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种能够推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间, 而是让父进程和子进程共享同-个拷贝.只有在须要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在须要写入的时候才进行,在此以前,只是以只读方式共享。线程
Linux 经过clone()系统调用实现fork()。这个调用经过一系列的参数标志来指明父、子进程须要共享的资源。
do_fork 完成了建立中的大部分工做,它的定义在kemeVfork.c 文件中。该函数调用copy_
process()函数,而后让进程开始运行。copy_process()函数完成的工做颇有意思:设计
除了不拷贝父进程的页表项外,vfork()系统调用和fork()的功能相同。3d
钱程机制是现代编程技术中经常使用的一种抽象概念. 该机制提供了在同一程序内共享内存地址
空间运行的一组线程。这些线程还能够共享打开的文件和其余资源.线程机制支持并发程序设计技术(concurrentprogramming),在多处理器系统上,它也能保证真正的井行处理( parallelism )。Linux实现线程的机制很是独特。从内核的角度来讲,它并无线程这个概念。Linux 把所
有的钱程都当作进程来实现。
内核常常须要在后台执行一些操做。这种任务能够经过内核线程( kernel thread)完成————独立运行在内核空间的标准进程。内核线程和普通的进程阔的区别在于内核线程没有独立的地址空间(实际上指向地址空间的mm指针被设置为NULL ).它们只在内核空间运行,历来不切换到用户空间去.内核进程和普通进程同样,能够被调度,也能够被抢占.
虽然让人伤感,但进程终归是要终结的(说得好像真的很伤感同样)。当一个进程终结时,内核必须释放它所占有的资掠并把这一不幸告知其父进程。
若是父进程在子进程以前退出,必须有机制来保证子进程能找到一个新的父亲,不然这些成为孤儿的进程就会在退出时永远处于僵死状态,白白地艳费内存。