學習Linux C程式設計之程序控制程式設計
建立程序 fork
fork 的定義
在 Linux 中,我們使用 fork
來建立一個子程序
fork 的返回值
fork 函式有些特殊,成功它返回 2 次,失敗返回 -1,利用這個特性可以判斷當前的程序是子程序還是父程序:
1. 在子程序中返回 0
2. 在父程序中返回子程序的程序 ID
fork 的寫時複製技術
通過執行 fork,子程序得到父程序的一個副本,例如子程序獲得父程序的資料空間,堆和棧的副本,但是它們並不共享儲存空間,它們只共享程式碼段。但是在現在的系統實現中,並不執行拷貝父程序的副本,作為替代方案,而是使用寫時複製(Copy - On - Write)技術。
寫時複製:在 fork 之後,這些區域由父子程序共享,而且核心將它們的訪問許可權改變為只讀,如果父子程序中的任何一個試圖修改這些區域,核心只為修改區域的那片記憶體製作一個副本給子程序。
不管是哪種技術實現,最後父子程序的資料都是獨立的,不會相互影響
子程序的執行位置
fork 還有一個特點:子程序不是從 main
函式開始執行的,而是從 fork 返回的地方開始
建立程序 vfork
還有一個建立程序的系統呼叫 vfork
,它跟 fork 很相似,但是也有幾點不同:
1. vfork 的目的是建立一個子程序來執行一個程式
2. vfork 並不復制父程序地址空間,子程序在父程序地址空間中執行
3. vfork 保證子程序先執行
4. 子程序需要呼叫 exec 或 exit 函式退出,否則會帶來未知結果。
exec
fork 函式裡面最後也是呼叫 exec 等函式來執行程式的
exec 有很多變種函式,例如 execlp
,execle
,等等,但基本的用法都是差不多的
執行結果就相當與 shell 命令:ps - ef
,其他的變種函式可以通過 man
exec
來檢視。
程序等待 wait
父程序可以使用 wait 系統呼叫主動等待子程序或者指定程序結束,並獲得子程序的結束資訊
這個系統呼叫的過程如下:
1. wait 暫停呼叫它的程序直到子程序結束
2. wait 呼叫成功返回子程序的 PID
3. wstatus 儲存子程序的返回資訊(正常退出,異常退出,被訊號殺死),以此來知道子程序是如何結束的
大致的流程如下:
F ---fork------> F -------- wait ----> F ------------->
| |
| |
| |
-------> C -------------exit() -
- 1
- 2
- 3
- 4
- 5
如果子程序呼叫 exit 退出,那麼核心將 exit 的退出狀態碼放在 status 中
如果程序被殺死,核心將訊號序列放在 status 中
實際使用時,wait 提供了相關的巨集來判斷 status 的狀態
程序結束
既然能夠建立程序,那肯定能夠結束程序,在 Linux 中程序退出又分為正常和異常退出,分別來了解了解。
正常退出
有 5 種正常退出程序的方法:
1. 在 main 內執行 return
,等價於呼叫 exit
2. 呼叫 exit
3. 呼叫 _exit
或 _Exit
4. 程序的最後一個執行緒在其啟動例程中執行 return 語句
5. 程序的最後一個執行緒呼叫 pthread_exit
函式
異常終止
有 3 種異常終止的方法:
1. 呼叫 abort
,產生 SIGABRT
訊號
2. 當程序接受到某些訊號時
3. 最後一個執行緒對「取消」請求作出響應
不管是哪種終止情況,我們都可以使用 wait
或者 waitpid
來得到子程序的退出狀態。