# linux读书笔记(3章)

linux读书笔记(3章)

标签(空格分隔): 20135328陈都

第三章 进程管理

3.1 进程

  • 进程就是处于执行期的程序(目标码存放在某种存储介质上)。但进程并不只仅局限于一段可执行程序代码( Unix称其为代码段,text section)。一般进程还要包含其余资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具备内存映射的内存地址空间及一个或多个执行线程(threa do fexecution),固然还包括用来存放全局变量的数据段等。linux

  • 程序自己并非进程,进程是处于执行期的程序以及相关的资源的总称。实际上,彻底可能存在两个或多个不一样的进程执行的是同一个程序。而且两个或两个以上并存的进程还能够共享许多诸如打开的文件、地址空间之类的资源。编程

  • 一般,建立新的进程都是为了当即执行新的、不一样的程序,而接着调用exec。这组函数就能够建立新的地址空间,并把新的程序载入其中。数组

  • 最终,程序经过exi的系统调用退出执行。这个函数会终结进程并将其占用的资源释放掉。父进程能够经过wait4()9系统调用查询子进程是否终结,这其实使得进程拥有了等待特定进程执行完毕的能力。进程退出执行后被设置为僵死状态,直到它的父进程调用wait()或waitpid()为止。并发

3.2进程描述符及任务结构

进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其余更多信息(见下图)
函数

3.2.1 分配避程描述符

  • 在x86 上, structtbre叫~info在文件<asm/也read_info.h>中定义以下:

每一个任务的thread_info 结构在色的内核栓的尾端分配。结构中task 域中存放的是指向该任务实际task_struct 的指针。spa

3.3进程建立

Unix 的进程建立很特别。许多其余的操做系统都提供了产生(spawn)进程的机制,首先在新的地址空间里建立进程,读入可执行文件,最后开始执行。Unix 采用了不同凡响的实现方式,它把上述步骤分解到两个单独的函数中去执行: forkO 和exec()首先,fork()经过拷贝当前进程建立一个子进程。子进程与父进程的区别仅仅在于PID(每一个进程惟一)、PPID(父进程的进程号,子进程将其设置为被拷贝进程的PID)和某些资源和统计量(例如,挂起的信号,它没有必要被继承〉。exec()函数负责读取可执行文件并将其载入地址空间开始运行。把这两个函数组合起来使用的效果跟其余系统使用的单一函数的效果类似。操作系统

3.3.1 写时拷贝

Linux 的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种能够推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间, 而是让父进程和子进程共享同-个拷贝.只有在须要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在须要写入的时候才进行,在此以前,只是以只读方式共享。线程

3.3.2 fork()

Linux 经过clone()系统调用实现fork()。这个调用经过一系列的参数标志来指明父、子进程须要共享的资源。
do_fork 完成了建立中的大部分工做,它的定义在kemeVfork.c 文件中。该函数调用copy_
process()函数,而后让进程开始运行。copy_process()函数完成的工做颇有意思:设计

  1. 调用dup_task_ struct()为新进程建立一个内核枝、也read_info结构和task_struct,这些值与当前进程的值相同。此时,子进程和父进程的描述符是彻底相同的。
  2. 检查并确保新建立这个子进程后,当前用户所拥有的进程数目没有超出绘色分配的资源的限制。
  3. 子进程着手使本身与父进程区别开来。进程描述符内的许多成员都要被清0 或设为初始值.那些不是继承而来的进程描述符成员,主要是统计信息。task_struct 中的大多数数据都依然未被修改。
  4. 子进程的状态被设置为TASK_UNJNTERRUPTIBLE,以保证它不会投入运行。
  5. copy _process()调用copy_flags()以更新task_struct 的组ags 成员.代表进程是否拥有超级用户权限的PF_SUPE盯RIV标志被清0。代表进程尚未调用exec()函数的PF_FOR.KNOEXEC标志被设置。
  6. 调用alloc _pid()为新进程分配一个有效的PID。
  7. 根据传递给clone()的参数标志,copy_process()拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。在通常状况下,这些资源会被给定进程的全部线程共享:不然,这些资源对每一个进程是不一样的,所以被拷贝到这里。
  8. 最后, copy_process()傲扫尾工做并返回一个指向子进程的指针。
    再回到do_fork()函数,若是copy_process()函数成功返回,新建立的子进程被唤醒并让其投入运行。内核有意选择子进程首先执行。.由于通常子进程都会立刻调用exec()函数,这样能够避免写时拷贝的额外开销,若是父进程首先执行的话,有可能会开始向地址空间写入。

3.3.3 vfork()

除了不拷贝父进程的页表项外,vfork()系统调用和fork()的功能相同。3d

3.4 线程在linux中的实现

钱程机制是现代编程技术中经常使用的一种抽象概念. 该机制提供了在同一程序内共享内存地址
空间运行的一组线程。这些线程还能够共享打开的文件和其余资源.线程机制支持并发程序设计技术(concurrentprogramming),在多处理器系统上,它也能保证真正的井行处理( parallelism )。Linux实现线程的机制很是独特。从内核的角度来讲,它并无线程这个概念。Linux 把所
有的钱程都当作进程来实现。

  • 传递给clone()的参数标志决定了新建立进程的行为方式和父子进程之间共辜的资源种类。下表列举了这些clone()周到的参数标志以及它们的做用,这些是在<linux/scbed.h>中定义的。
    -

3.4.2 内核编程

内核常常须要在后台执行一些操做。这种任务能够经过内核线程( kernel thread)完成————独立运行在内核空间的标准进程。内核线程和普通的进程阔的区别在于内核线程没有独立的地址空间(实际上指向地址空间的mm指针被设置为NULL ).它们只在内核空间运行,历来不切换到用户空间去.内核进程和普通进程同样,能够被调度,也能够被抢占.

3.5 进程终结

虽然让人伤感,但进程终归是要终结的(说得好像真的很伤感同样)。当一个进程终结时,内核必须释放它所占有的资掠并把这一不幸告知其父进程。

3.5.2 孤儿进程形成的进退维谷

若是父进程在子进程以前退出,必须有机制来保证子进程能找到一个新的父亲,不然这些成为孤儿的进程就会在退出时永远处于僵死状态,白白地艳费内存。

3.6 小结

  • 在本章中,咱们考察了操做系统中的核心概念一一进程。
  • 进程是一个很是基础、很是关键的抽象概念,位于每一种现代操做系统核心位置,也是咱们拥有操做系统的最终缘由。
相关文章
相关标签/搜索