Linux 系统中进程的创建和死亡

参考文档

Linux 进程的生与死
科技爱好者周刊(第 198 期):美国制造是否可能

这篇文章包含一个进程在 Linux 上 创建和销毁 的粗略描述。

创建

每次创建一个新的进程,真的是通过系统调用 fork 或者 clone 分裂出一个子进程。fork 完成后,进程通常运行 execve(系统调用)将当前正在执行进程与子进程进行切换。例如:当你在 bash shell 中运行一个 ls 命令时,父进程会利用 fork 分裂出一个子进程然后子进程去执行 ls。子进程执行完成后会死亡(销毁)最后只剩下开始的 bash shell 进程。

在实践中,程序从来不会直接调用 系统调用(系统级别的一些函数) - 他们使用 libc 包装器来代替 或者 类似 libc 函数的系统,该系统封装了使用 fork 和 execve 的细节(或者 execve 的几种变体)。

死亡(销毁)

进程如何死亡?大概有以下三种方式:

  1. 调用系统函数 exit 或者 exit_group。如果程序员没有显式调用 exit 并且是是从 main 方法返回,exit 是一定会执行的,因为 libc 编译器包装了 main,会在main退出后执行 exit。
  2. 如果使用的不是 libc 编译器,并且也没有显式的调用 exit 函数,那么从 main 返回 将导致 segfault 或者其他关键信号,因为 return 将试图从堆栈中弹出一个非法地址,这就是进程死亡的第二种方式,即通过 SIGTERM 或者 SIGKILL(反应的在 命令中 kill -9 $
  3. 拔掉计算机电源

身份标识和僵尸进程

每个进程都有独一无二的 pid - 或者说在内核回收这个 pid 之前是独一无二的。在一个进程回收之前,父进程应该在调用 wait,waitpid,或者 waitid。如果不调用,子进程将会变成 僵尸 进程。如果父进程本身死亡,那么该进程会被重新分配给一个pid为1的父进程--也就是唯一的init进程的pid,它会自动调用wait并释放该进程。

wait 系统调用:当功能为子进程运行时,会挂起调用进程,wait 经常会在 fork 之后被父进程调用。
waitpid 系统调用挂起调用进程的执行直到由参数 pid 指定的孩子的状态发生改变。

线程-较小的进程

在 Linux 中,线程或多或少是独立的进程,他们拥有相同的内存空间和一些其他资源。他们带有适当的标记,通过 clone(系统调用)创建出来。在内核术语中,每个线程有独一无二的 pid 并且 同一进程中的所有线程拥有相同的 tgid(线程组id)。这个 tgid 等于 第一个线程的 pid。因此,从内核角度看,真正的 pid 指线程,tgid 指的是进程,对于单进程线程,pid 等于 tgid。

What makes this confusing is that the terminology in usermode is different as you can see in the following table:

Kernel name (in task_struct) Usermode name Returned by syscall
tgid (thread group id) pid (process id) getpid
pid (process id) tid (thread id) gettid, clone, fork

# linux 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×