每個進程除了一定有PID還會有PPID,也就是父進程ID,通過PPID可以找到父進程的信息。
為什么進程都會有父進程ID呢?因為進程都是由父進程衍生出來的,后面會詳細介紹幾種衍生的方法。那么跟人類起源問題一樣,父進程的父進程的父進程又是什么呢?實際上有一個PID為1的進程是由內(nèi)核創(chuàng)建的init進程,其他子進程都是由它衍生出來,所以前面的描述并不準確,進程號為1的進程并沒有PPID。
因為所有進程都來自于一個進程,所以Linux的進程模型也叫做進程樹。
要想獲得進程的PPID,可以通過以下Getppid()這個函數(shù)來獲得,print_ppid.go程序的代碼如下。
package main
import (
"fmt"
"os"
)
func main() {
fmt.Println(os.Getppid())
}
root@87096bf68cb2:/go/src# go run print_ppid.go
2892
root@87096bf68cb2:/go/src# go run print_ppid.go
2902
有趣的事情發(fā)生了,有沒有發(fā)現(xiàn)每次運行的父進程ID都不一樣,這不符合我們的預期啊,原來我們通過go run每次都會啟動一個新的Go虛擬機來執(zhí)行進程。
如果我們先生成二進制文件再執(zhí)行結(jié)果會怎樣呢?
root@87096bf68cb2:/go/src# ./print_ppid
1
root@87096bf68cb2:/go/src# ./print_ppid
1
root@87096bf68cb2:/go/src# ps aux |grep "1" |grep -v "ps" |grep -v "grep"
root 1 0.0 0.3 20228 3184 ? Ss 07:25 0:00 /bin/bash
這次我們發(fā)現(xiàn)父進程ID都是一樣的了,而且通過ps命令可以看到父進程就是bash,說明通過終端執(zhí)行命令其實是從bash這個進程衍生出各種子進程。
為了執(zhí)行這個程序要查找包依賴、編譯、打包、鏈接(和go build做一樣的東西)然后執(zhí)行,這是全新的進程。
拿到PID和PPID后有什么用呢?馬上揭曉。