行程與行程抽象

exec(替換行程映像)

/ exec, 'EX-eck' /

想像一位演員,不離開舞臺、節目單上的名字也不變,卻徹底換了角色:新臺詞、新戲服、新身分,同一具身體。exec 系統呼叫對行程做的正是這件事:它保留同一個行程(同一個 PID),卻替換它正在執行的內容——丟掉當前的程式,把一個全新的程式載入到原處,從頭開始執行。

當行程呼叫 exec 家族的某個成員(例如 execve)時,作業系統丟棄該行程當前的位址空間——它的文字、資料、堆積與堆疊——並把所要求的可執行檔從磁碟載入到一個全新的位址空間:新程式的程式碼放進文字區段、它的資料放進資料區與 BSS、一個新的堆疊,依此類推。接著從新程式的進入點開始執行。關鍵在於,PID 以及通常開啟的檔案維持不變;被換掉的只有正在執行的程式。若 exec 成功,它永遠不會返回舊的程式碼,因為那段程式碼已不存在;只有在載入失敗時它才(帶著錯誤)返回。

exec 是 Unix「建立一個行程」慣用法的一半:fork 複製出你自己,然後 exec 把那個副本變成你真正想執行的程式。這種拆分很優雅,因為它讓子行程在 fork 與 exec 之間那一小段時間裡,先調整自己的環境(重導輸入輸出、改變權限)再變成新程式。一個常見的混淆是期待 exec 啟動一個全新、獨立的行程;它不會。它就地把呼叫它的行程變身。要讓一個獨立的行程執行新程式,你得先 fork,再在子行程裡 exec。

命令列直譯器想執行「ls」時先 fork;子行程接著對 /bin/ls 呼叫 execve。子行程的 PID 不變,但它的程式現在是 ls,從頭開始執行。父行程(直譯器)等它結束。

同一個行程(同一個 PID),原處載入了一個全新的程式。

exec 不建立行程;它在既有行程內(同一個 PID)替換正在執行的程式。成功的 exec 永遠不返回,因為舊的程式碼已經消失。

又稱
exec()exec familyexecve替換映像載入新程式