进程线程的生与死

本文介绍了UNIX系统中进程的创建,包括fork和vfork的区别,以及进程的生命周期。当父进程先于子进程结束时,子进程由init接管,避免僵死进程。反之,子进程结束会通知父进程,等待确认或父进程终止。此外,讨论了内核态、用户态和中断上下文的概念,以及线程作为微进程的角色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

UNIX 进程是在某个进程调用 fork 时创建的,fork 将正在运行的可执行进程一分为二。子进程将分配到内核栈,栈尾有一个thread_struct结构体,这个结构体有一个指针指向该进程描述符task_struct。另外还会分到独立的4G的地址空间。当然这个是虚拟地址空间,由mm_struct结构体表示,mm_struct结构体里还会有成员指示实际分配到的物理地址的情况。根据缺页机制,将在需要的时候才会为虚拟地址空间分配适当大小的物理地址空间。还有其他,如文件描述符、一些变量等等。然后该进程可以执行 exec 系列中的某个系统调用,从而将当前运行的映像替换为新的映像。


当父进程先于子进程终止时,其所有子进程将由 PID 为 1 的 init 接纳。init是一个永远调用wait函数的进程。这样就不会产生僵死进程了。这个是在设计系统init时就是这样设计的。


如果子进程在父进程之前终止,则会向父进程发送一个信号,然后子进程转变为僵死状态,直到该信号得到确认,或父进程被终止。这种情况详细分析如下:
每个进程都有一个父进程,当进程退出时,其退出状态可以被父进程得到。进程退出后,它的很多资源都将被释放。比如如果没有其他进程共享,它会释放mm_struct,还有内核栈和thread_struct。只剩下task_struct还被留在内核并占用pid号。父进程调用wait函数取得子进程的退出状态信息,通过读取进程描述符得到退出状态信息,并将子进程的ID和该进程描述符从系统的进程表中删除。这些退出状态信息保存在内核中,占用很小的一块内存空间。如果不调用wait函数,则父进程得不到子进程的退出信息,子进程的ID会一直保存在系统的进程列表中。所以,此时对于系统而言,子进程还是一个却是存在的进程,占据着一个ID。由于linux系统下是有严格的进程数限制的,所以子进程退出时ID不从进程列表中删除,将会是系统安全的一个重大隐患。那么,如果没用wait函数,ID会不会一直存在下去呢?也不会,只要它的父进程终止,则子进程的ID自然也会同父进程一起被注销。注意这里的终止,指的是只要是父进程被终止。可以是父进程的父进程调用wait等函数使终止,也可以是父进程的父进程没用调用wait函数使终止。由于子进程的退出信息保存占用的是父进程的资源,所以当父进程退出时,保存子进程退出信息占用的这些空间自然也被释放了。

fork与vfork的区别:
(1)fork():使用fork()创建一个子进程时,子进程只是完全复制父进程的资源。这样得到的子进程独立于父进程具有良好的并发性。
 vfork(): 使用 vfor创建一个子进程时,操作系统并不将父进程的地址空间完全复制到子进程。而是子进程共享父进程的地址空间,即子进程完全运行在父进程的地址空间上。子进程对该地址空间中任何数据的修改同样为父进程所见。
(2)fork():父子进程执行顺序不定;
vfork():保证子进程先运行,在调用exec或exit之前与父进程共享数据,在它调用exec或exit之后父进程才可能被调度运行。
(3)vfork保证子进程先运行,在它调用exec或exit后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。
(4)在vfork创建的子进程后,父进程进入阻塞状态,子进程运行。等到调用exit或exec后子进程才复制父进程资源到自己独有的地址空间去。这个时候的父子进程才和fork创建的父子进程关系相同。也只有这个时候父进程才开始继续运行。当然子进程一直在运行。

处理器总处于以下状态中的一种:
1、内核态,运行于进程上下文,内核代表进程运行于内核空间;
2、内核态,运行于中断上下文,内核代表硬件运行于内核空间;
3、用户态,运行于用户空间

用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存器值、变量等。所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等。

  硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。所谓的“中断上下文”,其实也可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被打断执行的进程环境)。

LINUX完全注释中的一段话:
  当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程的执行。


线程在内核中跟进程没多大区别,可以说是微进程。根据线程的产生机制,分为内核线程和用户线程。

另外有个考点:线程和进程都可以并发执行。

参考文章 http://blog.youkuaiyun.com/zhiyu520/archive/2008/07/27/2719827.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值