linux内核——从fork()看进程管理

众所周知,linux系统中,进程的创建一般由fork( )或者exec( )来实现。然而,理解fork( )背后所做的工作是很有必要的,有助于我们更好地理解进程之间的通信。在此之前,我们先来介绍几种关于进程的结构。

一、任务结构与进程描述符

首先,内核中有一个包括所有进程的列表,叫做任务队列。它是一个双向循环链表,链表中的每一项类型都是task_struct,称为进程描述符的结构。(定义在内核<linux/sched.h>中)

进程描述符所包含的信息有:

① 标识符:唯一,用来区分进程。

② 状态:运行态等;

③ 优先级;

④ 程序计数器:下一条指令的地址;

⑤ 内存指针;

⑥ 上下文数据:程序运行时寄存器中的数据;

⑦ I/O状态信息:包括显式的I/O请求、分配给进程的设备等等;

⑧ 记账信息;


二、进程的状态

进程在运行的过程中会有多次状态切换,总的来说有5种状态:

运行态:进程正在执行;

就绪态:进程准备执行;

阻塞/等待态:进程在某些事件发生之前不能执行;

新建态:刚刚创建,还没执行;(没加载到内存中)

退出态:准备退出,释放内存;

 

三、回到fork( )

首先,fork( )通过拷贝当前进程来创建一个子进程(写时拷贝技术,后面会介绍)。父子进程的区别仅仅是PID、PPID、以及一些统计量不同而已。exec()函数负责读取可执行文件并将其载入到地址空间开始运行。所以,fork()会返回两次,返回到父进程时返回值等于0,返回到子进程时返回值小于0,编程的时候正是通过返回值来区分父子进程。

接下来介绍写时拷贝。传统的fork()直接把所有的资源复制给子进程,这样过于简单且效率低下,并且拷贝的数据也许不共享。更糟的是,如果子进程打算立即执行一个新的映像(exec),所有的拷贝将前功尽弃。所有,现在的fork( )用写时拷贝来实现。宗旨就是推迟甚至免除拷贝数据。最开始,内核并不复制整个进程地址空间,而是让父子进程共享一个拷贝,在写入之前,以自读的方式共享。当需要写入的时候,数据才会被复制,从而各个进程拥有各自的拷贝。这样使得linux有了进程快速执行的能力,也是最大的优点。

fork()接下来的工作就好理解了。

1、为新进程分配相关资源,如内核栈,进程描述符等。此时的子进程和父进程的描述符是完全相同的。

2、检查进程总数是否超过系统上限。(对于普通用户一般不会)

3、将子进程与父进程区分开来。进程描述符内很多数据将被清0或者改变。

4、将子进程设置为不可中断型,保证它不会投入运行。

5、为新进程分配有效的PID。

6、拷贝或者共享打开的文件,文件系统信息、信号处理函数等等。

值得注意的是,内核会有意让子进程先执行,因为一般子进程会马上调用exec()函数,这样可以避免写时拷贝的额外开销。否则,如果父进程先执行并且写入数据,可能会做一次无用的写时拷贝。


四、线程在linux中的实现

为什么有了进程,还要创建线程机制呢?因为有时候一个进程还是太大了,linux是抢占式的,将一个进程分成多个线程来执行能提高效率。线程机制支持并发程序设计,可以真正的并行处理。

对linux内核来说,并没有线程这个概念。它会把线程当做进程来实现,线程仅仅被视作一个与其他进程共享资源的进程。不过,创建的线程会与父进程共享地址空间、文件系统资源、文件描述符、信号处理程序。

不得不提到一种特殊的线程——内核线程。内核进程需要后再执行一些操作,就由内核线程来完成。它和普通进程的区别在于内核线程没有独立的地址空间。它只在内核空间运行,从不切换到用户空间。不过,他也可以被调度,被抢占。


五、进程的终止与孤儿进程

进程总是要终止的,所有的进程在终止时都会调用do_exit( )来完成终止的一部分操作。(注意只是一部分)执行完do_exit()之后,进程会进入僵死状态,等待父进程来收尾(waitpid)。此时,系统会保留它的进程描述符。这样使得系统可以在子进程终止后仍然能获得它的信息。所以,清理工作和进程描述符的删除是分开进行的。在父进程获得子进程的信息之后,或者通知内核它并不关注那些信息后,子进程的进程描述符才会被释放。

接下来问题就来了,如果父进程在子进程之前就终止了呢?linux给出的解决办法是,给子进程在当前线程组找一个线程当做父亲,如果不行,就把init()当做他的父亲。这样就避免了孤儿进程的僵死状况。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值