基於fork的多進程編程
fork使用
pid = os.fork()
功能: 創建新的進程
返回值:整數,如果創建進程失敗返回一個負數,如果成功則在原有進程中返回新進程的PID,在新進程中返回0
注意:
- 子進程會復制父進程全部內存空間,從fork下一句開始執行。
- 父子進程各自獨立運行,運行順序不一定。
- 利用父子進程fork返回值的區別,配合if結構讓父子進程執行不同的內容幾乎是固定搭配。
- 父子進程有各自特有特征比如PID PCB 命令集等。
- 父進程fork之前開辟的空間子進程同樣擁有,父子進程對各自空間的操作不會相互影響。

1 import os 2 from time import sleep 3 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")

1 import os 2 from time import sleep 3 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)
進程相關函數
os.getpid()
- 功能: 獲取一個進程的PID值
- 返回值: 返回當前進程的PID
os.getppid()
- 功能: 獲取父進程的PID號
- 返回值: 返回父進程PID

1 # 獲取pid值 2 3 import os 4 import time 5 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())
os._exit(status)
- 功能: 結束一個進程
- 參數:進程的終止狀態
sys.exit([status])
- 功能:退出進程
- 參數:整數 表示退出狀態
- 字符串 表示退出時打印內容

1 import os 2 import sys 3 4 # os._exit(1) 5 sys.exit("退出進程") 6 7 print("Process exit")
孤兒和僵屍
1.孤兒進程 : 父進程先於子進程退出,此時子進程成為孤兒進程。
特點: 孤兒進程會被系統進程收養,此時系統進程就會成為孤兒進程新的父進程,孤兒進程退出該進程會自動處理。
2.僵屍進程 : 子進程先於父進程退出,父進程又沒有處理子進程的退出狀態,此時子進程就會稱為僵屍進程。
特點: 僵屍進程雖然結束,但是會存留部分PCB在內存中,大量的僵屍進程會浪費系統的內存資源。
3.如何避免僵屍進程產生
1)使用wait函數處理子進程退出
```
pid,status = os.wait()
功能:在父進程中阻塞等待處理子進程退出
返回值: pid 退出的子進程的PID status 子進程退出狀態 ```

1 import os 2 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 while True: 16 pass
2)創建二級子進程處理僵屍
- 父進程創建子進程,等待回收子進程
- 子進程創建二級子進程然后退出
- 二級子進程稱為孤兒,和原來父進程一同執行事件

1 import os 2 from time import sleep 3 4 def f1(): 5 for i in range(4): 6 sleep(2) 7 print("寫代碼") 8 9 def f2(): 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 import signal 2 import os 3 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 while True: 15 pass