跳转至

fork 例

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# learnfork.py
# 我们在shell中使用`python3 learnfork.py`执行这段Python代码

import os
import time

# 这个Python文件对应的进程被shell创建并开始执行
# 其实这个进程就是一个Python3的解释器

pid = os.fork()
# 注意这里fork()只被Python文件对应的进程调用了一次
# 在fork()执行的过程中 当前进程的空间被复制了一份给子进程
# fork()执行结束之后 pid会分别在父进程和子进程返回
# 子进程得到的是0 父进程得到的是子进程的pid

# 此时已经有两个进程在同时运行 注意这里同时说的是时间片轮转两个程序都会参与调度运行
if pid < 0:  # fork失败
    print("fork失败 退出当前进程")
    exit()

if pid >= 1:  # 当前的程序是父进程 成功创建了子进程 而且拿到了子进程的pid
    print(f"[父进程] 我是父进程(pid{os.getpid()}) 创建了子进程(pid{pid}) 由shell(pid{os.getppid()})创建")
    print("[父进程] 干自己的事情...")
    time.sleep(5)
    # pid, result = os.waitpid(pid, 0)
    # # https://docs.python.org/3/library/os.html#os.waitpid
    # print(f"[父进程] 子进程(pid{pid})退出 返回值为{result >> 8}")
    print("[父进程] 退出")
    exit(0)
elif pid == 0:  # 当前的程序是新创建出的子进程 可以开始做一些子进程的事情了
    print(f"[子进程] 我是子进程(pid{os.getpid()}) 由父进程(pid{os.getppid()})创建")
    print("[子进程] 干自己的事情...")
    time.sleep(10)
    print("[子进程] 退出")
    exit(0)

# 父进程和子进程各自执行完自己的三个print会退出
# 但其实并不是这样的
# 如果父进程先结束 父进程结束后子进程按理说会成为僵尸进程 除非被系统接管
# 如果子进程先结束 父进程应该对应的回收子进程(learnfork.py并没有考虑回收) 父进程结束后子进程按理说僵尸进程 除非被系统接管
# 嘛 也就是说这个程序 不考虑操作系统 无论如何子进程都会成为僵尸进程

# 当父进程`sleep(5)`而子进程`sleep(10)`的输出情况如下:
#
# $ python3 learnfork.py # 1
# [父进程] 我是父进程(pid92336) 创建了子进程(pid92337) 由shell(pid90821)创建 # 2
# [父进程] 干自己的事情... # 3
# [子进程] 我是子进程(pid92337) 由父进程(pid92336)创建 # 4
# [子进程] 干自己的事情... # 5
# [父进程] 退出 # 6
# $ [子进程] 退出 # 7
#
# 第1行为我们手敲的 回车之后
# 第2-5行瞬间输出
# 等5秒之后第6行输出
# 这时shell认为它fork的Python3解释器已经结束运行了 然后就在第7行输出了一个`$`
# 等5秒之后第7行输出子进程结束的信息 注意这说明父进程结束运行之后子进程还在运行 这应该是操作系统进行了接管

# 作修改添加父进程回收子进程的代码:
# 在父进程最后一行代码前添加`pid, result = os.waitpid(pid)`即可让父进程等待子进程结束运行
# 取消父进程代码中的三行注释
# 输出结果如下:
#
# $ python3 learnfork.py
# [父进程] 我是父进程(pid93225) 创建了子进程(pid93226) 由shell(pid90821)创建
# [父进程] 干自己的事情...
# [子进程] 我是子进程(pid93226) 由父进程(pid93225)创建
# [子进程] 干自己的事情...
# [子进程] 退出
# [父进程] 子进程(pid93226)退出 返回值为8
# [父进程] 退出