基于fork的多进程编程
fork使用
pid = os.fork()
功能: 创建新的进程
返回值:整数,如果创建进程失败返回一个负数,如果成功则在原有进程中返回新进程的PID,在新进程中返回0
注意:
子进程会复制父进程全部内存空间,从fork下一句开始执行。
父子进程各自独立运行,运行顺序不一定。
利用父子进程fork返回值的区别,配合if结构让父子进程执行不同的内容几乎是固定搭配。
父子进程有各自特有特征比如PID PCB 命令集等。
父进程fork之前开辟的空间子进程同样拥有,父子进程对各自空间的操作不会相互影响。
1 importos2 from time importsleep3
4 pid =os.fork()5
6 if pid <0:7 print("Create process failed")8 elif pid ==0:9 os._exit(0)10 sleep(3)11 print("New process")12 else:13 sleep(5)14 print("Old process")15
16 print("Fork test end")
基于fork的进程创建演示1
1 importos2 from time importsleep3
4 print("=========================")5 a = 1
6
7 pid =os.fork()8
9 if pid <0:10 print("Create process failed")11 elif pid ==0:12 print("New process")13 print("a =",a)14 a = 10000
15 else:16 sleep(1)17 print("Old process")18 print("a:",a)19
20 print("All a =",a)
基于fork的进程创建演示2
进程相关函数
os.getpid()
功能: 获取一个进程的PID值
返回值: 返回当前进程的PID
os.getppid()
功能: 获取父进程的PID号
返回值: 返回父进程PID
1 #获取pid值
2
3 importos4 importtime5
6 pid =os.fork()7
8 if pid <0:9 print("Error")10 elif pid ==0:11 time.sleep(1)12 print("Child PID:",os.getpid())13 print("Get parent PID:",os.getppid())14 else:15 print("Get child PID:",pid)16 print("Parent PID:",os.getpid())
get_pid
os._exit(status)
功能: 结束一个进程
参数:进程的终止状态
sys.exit([status])
功能:退出进程
参数:整数 表示退出状态
字符串 表示退出时打印内容
1 importos2 importsys3
4 #os._exit(1)
5 sys.exit("退出进程")6
7 print("Process exit")
exit
孤儿和僵尸
1.孤儿进程 : 父进程先于子进程退出,此时子进程成为孤儿进程。
特点: 孤儿进程会被系统进程收养,此时系统进程就会成为孤儿进程新的父进程,孤儿进程退出该进程会自动处理。
2.僵尸进程 : 子进程先于父进程退出,父进程又没有处理子进程的退出状态,此时子进程就会称为僵尸进程。
特点: 僵尸进程虽然结束,但是会存留部分PCB在内存中,大量的僵尸进程会浪费系统的内存资源。
3.如何避免僵尸进程产生
1)使用wait函数处理子进程退出
```
pid,status = os.wait()
功能:在父进程中阻塞等待处理子进程退出
返回值: pid 退出的子进程的PID
status 子进程退出状态
```
1 importos2
3 pid =os.fork()4
5 if pid <0:6 print("Error")7 elif pid ==0:8 print("Child process",os.getpid())9 os._exit(3)10 else:11 p,status = os.wait() #阻塞等待子进程退出
12 print("p :",p)13 #还原退出状态
14 print("status:",os.WEXITSTATUS(status))15 whileTrue:16 pass
wait 处理僵尸
2)创建二级子进程处理僵尸
父进程创建子进程,等待回收子进程
子进程创建二级子进程然后退出
二级子进程称为孤儿,和原来父进程一同执行事件
1 importos2 from time importsleep3
4 deff1():5 for i in range(4):6 sleep(2)7 print("写代码")8
9 deff2():10 for i in range(5):11 sleep(1)12 print("测代码")13
14 pid =os.fork()15 if pid <0:16 print("Error")17 elif pid ==0:18 p = os.fork() #二级子进程
19 if p ==0:20 f2()21 else:22 os._exit(0) #一级子进程退出
23 else:24 os.wait() #等一级子进程退出
25 f1()
二级子进程处理僵尸
3)通过信号处理子进程退出
原理: 子进程退出时会发送信号给父进程,如果父进程忽略子进程信号,则系统就会自动处理子进程退出。
方法: 使用signal模块在父进程创建子进程前写如下语句 :
import signal
signal.signal(signal.SIGCHLD,signal.SIG_IGN)
特点 : 非阻塞,不会影响父进程运行。可以处理所有子进程退出
1 importsignal2 importos3
4 #子进程退出时父进程会忽略,此时子进程自动由系统处理
5 signal.signal(signal.SIGCHLD,signal.SIG_IGN)6
7 pid =os.fork()8
9 if pid <0:10 pass
11 elif pid ==0:12 print("Child pid:",os.getpid())13 else:14 whileTrue:15 pass
信号方法处理僵尸进程