os.fork()创建父子进程实现多任务编程
import os
pid = os.fork()
if pid < 0:
print(“创建进程失败”)
elif pid == 0:
print(“新创建的进程”)
else: # 即pid大于0的代码块,可以在此代码块中获取新进程的进程号
print(“原来的进程”)
- 功能:创建一个新的进程
- 参数:无
- 返回值:
- 失败:返回-1
- 成功:在原有进程中返回新进程的pid号(大于0的正整数)
在新进程中返回0
说明:
- *fork之前的代码只有父进程会执行
- *子进程会复制父进程全部代码段,包括fork之前产生的内存空间
- *子进程从fork的下一行开始执行
- *子进程通常会根据fork的返回值的差异选择执行不同的代码
- *子进程虽然复制父进程的代码空间,但是有自己的特有属性,比如PID号PCB等
- *父子进程在执行上互不干扰,执行顺序不确定
- *父子进程空间独立,在本进程中对空间的操作不会影响到其他进程
获取进程号:
-
os.getpid()
功能:获取当前进程的进程号
返回值:返回进程号 -
os.getppid()
功能:获取父进程进程号
返回值:返回进程号
进程的退出:
-
os._exit(status)
功能:退出进程
参数:进程的退出状态 整数(1:异常退出 , 0:正常退出) -
sys.exit([status])
功能:退出进程
参数:不写时默认为0
传入一个整数表示退出状态
传入一个字符串,则在进程退出时打印该字符串sys.exit
可以通过捕获SystemExit
异常,阻止其异常退出
示例演示1:
import os
from time import sleep
#fork之前的代码只有父进程会执行
print("*"*30)
#fork之前产生内存空间的储存,子进程也会有
#创建新的进程
pid=os.fork()
if pid<0:
print("创建进程失败")
#只有子进程执行的部分
elif pid==0:
sleep(3)
print("新创建的进程")
#只有父进程运行的部分
else:
sleep(5)
print("原来的进程")
#if结构外的代码,父子结构都会执行
print("程序执行完毕")
fatpuffer@ubuntu:~/mysocket$ python3 fork.py
******************************
***(3s后打印)***
新创建的进程
程序执行完毕
***(5秒后打印)***
原来的进程
程序执行完毕
- 由此来看,我们创建的父子进程运行上互不干扰,且在
if
语句块之外的代码父子进程都会执行。
示例演示2:
import os
from time import sleep
#创建新的进程
pid=os.fork()
a = 1
if pid < 0:
print("创建进程失败")
#只有子进程执行的部分
elif pid == 0:
print("a=",a)
a = 10000
print("新创建的进程")
print("a=",a)
#只有父进程运行的部分
else:
sleep(1)
print("原来的进程")
print("a=",a)
#if结构外的代码,父子结构都会执行
print("程序执行完毕")
fatpuffer@ubuntu:~/mysocket$ python3 fork.py
a= 1
新创建的进程
a= 10000
程序执行完毕
***(1秒后输出)***
原来的进程
a= 1
程序执行完毕
- 由此可见,
fork
之后的代码子进程也会拥有,且父子进程空间独立,互不干扰,虽然子进程将变量a
重新赋值为100
,单父进程拿到的结果依然是1
。
示例演示3:
import os
from time import sleep
#创建新的进程
pid=os.fork()
if pid<0:
print("创建进程失败")
elif pid==0: # 子进程空间
#获取当前进程号
print("子进程PID",os.getpid())
#获取父进程号
print("父进程PID",os.getppid())
else: # 父进程空间
# 创建成功,在原有进程中返回新进程的pid号
print("父进程PID",os.getpid())
print("子进程PID",pid) # 即子进程进程号
fatpuffer@ubuntu:~/mysocket$ python3 fork.py
父进程PID 2863
子进程PID 2864
子进程PID 2864
父进程PID 2863
- 创建进程成功,在原有进程中返回新进程的
pid
号
接下来我们来说说僵尸进程
孤儿进程的形成:
- 父进程先于子进程退出,此时子进程会成为孤儿进程。
孤儿进程特征:
- 孤儿进程会被系统指定的进程收养,即系统进程会成为孤儿进程新的父进程,当孤儿进程退出时,“继父”会处理孤儿进程退出状态,使其不会成为僵尸进程
僵尸进程的形成:
- 子进程先于父进程退出,父进程没有处理子进程的退出状态,此时子进程就会称为僵尸进程
僵尸进程的危害:
- 僵尸进程会滞留部分pcd信息在内存中,大量的僵尸进程会消耗系统资源,应尽量避免僵尸进程的产生。
如何表面僵尸进程的产生:
- 1、让父进程先退出(不佳,因为不好控制)
- 2、父进程处理子进程的退出状态
父进程处理子进程状态的方法:
(1)在父进程中阻塞等待子进程的退出os.wait()
- 返回值:
-
pid
:退出的子进程的PID号 -
status
:退出的子进程的退出状态
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("Creat process failed")
elif pid == 0:
sleep(3)
print("Child process over")
os._exit(3)
else:
# 等待子进程执行完毕
pid,status = os.wait()
print("*"*30)
print(os.WEXITSTATUS(status)) # 获取退出状态
print(pid,status)
while True:
pass
fatpuffer@ubuntu:~/mysocket$ python3 fork.py
Child process over
******************************
3
3042 768
(2)非阻塞循环等待子进程退出os.waitpid(pid,option)
- 参数:
-
pid
: - -1:表示等待任意子进程退出
- >0:表示等待对应PID号的子进程退出
-
option
: - 0: 表示阻塞等待
- WNOHANG: 表示非阻塞(os.WNOHANG)
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("Creat process failed")
elif pid == 0:
sleep(3)
print("Child process over")
os._exit(3)
else:
while True:
sleep(1)
#设置非阻塞状态
pid,status = os.waitpid(-1,os.WNOHANG)
print("*"*30)
#print(os.WEXITSTATUS(status))#获取推出状态
print(pid,status)
while True:
pass
fatpuffer@ubuntu:~/mysocket$ python3 fork.py
******************************
0
0 0
Child process over
waitpid(-1,0)=====wait():此时二者等价
import os
from time import sleep
pid = os.fork()
if pid < 0:
print("Creat process failed")
elif pid == 0:
sleep(3)
print("Child process over")
os._exit(3)
else:
while True:
sleep(1)
#设置非阻塞状态
pid,status = os.waitpid(-1,0)
print("*"*30)
#print(os.WEXITSTATUS(status))#获取推出状态
print(pid,status)
while True:
pass
fatpuffer@ubuntu:~/mysocket$ python3 fork.py
Child process over
******************************
3
2985 768
(3)创建二级父子进程
- 原理:子进程创建二级父子进程,然后让二级父进程直接退出,使得二级子进程成为孤儿进程,在执行完任务后自动被系统回收,这样一来就不会存在,子进程死掉后父进程没有处理,使其变为僵尸进程的情况。
#创建二级子进程处理僵尸
import os
from time import sleep
def fun1():
sleep(3)
print("第一件事情")
def fun2():
sleep(4)
print("第二件事情")
pid = os.fork()
if pid < 0:
print("create process failed")
# 子进程
elif pid == 0:
#创建二级子进程
pid0 = os.fork()
if pid0 < 0:
print("create process failed")
# 子进程
elif pid0 == 0:
fun2()
# 父进程
else:
# 父进程直接退出,让子进程成为孤儿进程,执行完任务后自动被系统回收
os._exit(0)
# 父进程
else:
os.wait()
fun1()#做第一件事情