linux系統(tǒng)編程-day10-進程管理(2)

vfork( ):

上節(jié)學(xué)習(xí)了fork( )時的寫時復(fù)制機制,實際上在早期并沒有實現(xiàn)寫時復(fù)制,在實現(xiàn)COW之前,Unix的設(shè)計者們就一直很關(guān)注在fork后立刻執(zhí)行exec所造成的地址空間的浪費。
BSD的開發(fā)者們在3.0的BSD系統(tǒng)中引入了vfork( )系統(tǒng)調(diào)用:

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);
  • 除了子進程必須要立刻執(zhí)行一次對exec的系統(tǒng)調(diào)用,或者調(diào)用_exit( )退出,對vfork( )的成功調(diào)用所產(chǎn)生的結(jié)果和fork( )是一樣的。
  • vfork( )會掛起父進程直到子進程終止或者運行了一個新的可執(zhí)行文件的映像。通過這種方式,vfork( )避免了地址空間的按頁復(fù)制。
  • 在這個過程中,父進程和子進程共享相同的地址空間和頁表項(不使用寫時復(fù)制)。實際上,vfork( )只完成了一件事:復(fù)制內(nèi)部的內(nèi)核數(shù)據(jù)結(jié)構(gòu)。因此,子進程也就不能修改地址空間中的任何內(nèi)存。
    長度。

終止進程

POSIX和C89都定義了終止當(dāng)前進程的標(biāo)準(zhǔn)函數(shù):

#include <stdlib.h>
void exit(int status);

對exit( )的調(diào)用通常會執(zhí)行一些基本的終止進程的步驟,然后通知內(nèi)核終止這個進程。
status參數(shù)用來標(biāo)識進程退出的狀態(tài):

  • EXIT_SUCCESS表示成功.
  • EXIT_FAILURE表示失敗.

在Linux中,0通常表示成功;非零值,例如1或者-1,表示失敗。
進程成功的退出時,只需要簡單的寫上:
exit(EXIT_SUCCESS);
在終止進程之前,C語言函數(shù)執(zhí)行以下關(guān)閉進程的工作:

  1. 以在系統(tǒng)中注冊的逆序來調(diào)用由atexit( )或on_exit( )注冊的函數(shù)
  2. 清空所有已打開的標(biāo)準(zhǔn)I/O流
  3. 刪除由tmpfile( )創(chuàng)建的所有臨時文件
    這些步驟完成了在用戶空間中所需做的事情,這樣exit( )就可以調(diào)用_exit( )來讓內(nèi)核來處理終止進程的剩余工作了:
#include <unistd.h>
void _exit(int status);

當(dāng)進程退出時,內(nèi)核會清理進程所創(chuàng)建的、不再用到的任何資源。這包括且不僅限于這些:申請的內(nèi)存、打開的文件和system V的信號量。
清理完成后,內(nèi)核摧毀進程,并告知父進程其子進程的終止。

  • 應(yīng)用程序可以直接調(diào)用_exit( ),但這通常是不合適的,但vfork( )的使用者終止進程必須使用_exit( ),而不是exit( )。
  • ISO C99標(biāo)準(zhǔn)中增加了_Exit( )函數(shù),它的功能和_exit( )是一樣的:
#include <stdlib.h>
void _Exit(int status);

  • 其他終止進程的方式
  1. 典型方式:并非通過明確的使用一個系統(tǒng)調(diào)用,而是采用跳轉(zhuǎn)到程序結(jié)尾處的方式。(例如在main( )函數(shù)返回時明確給出一個狀態(tài)值,或者調(diào)用exit( ),成功時的返回是exit(0), 或者是從main( )函數(shù)返回0)
  2. 如果進程收到一個信號,并且這個信號對應(yīng)的處理函數(shù)是終止進程,進程也會終止。這樣的信號包括SIGTERM和SIGKILL。
  3. 進程被內(nèi)核懲罰性的終止。內(nèi)核就會殺死執(zhí)行非法指令,引起一個段錯誤,或者內(nèi)存耗盡的進程。

atexit( )

atexit( )用來注冊一些在進程結(jié)束時要調(diào)用的函數(shù):

#include <stdlib.h>
int atexit (voidf (*function)(void));

對atexit( )的成功調(diào)用會把指定的函數(shù)注冊到進程正常結(jié)束時調(diào)用的函數(shù)中。

  • 如果進程調(diào)用了exec,所注冊的函數(shù)列表會被清除(因為這些函數(shù)不存在于新進程的地址空間中)
  • 如果進程是通過信號而結(jié)束的,這些注冊的函數(shù)也不會被調(diào)用。

要注冊的函數(shù)必須是無參且沒有返回值的,原型像這樣:

void my_function(void);

被注冊的函數(shù)以棧存儲,所以調(diào)用方式是FIFO的,先注冊的后調(diào)用。

  • 注冊的函數(shù)不能調(diào)用exit( ),否則會引起無限的遞歸調(diào)用。如果需要提前結(jié)束進程,應(yīng)該調(diào)用_exit( ),但是不推薦這樣做。
  • POSIX標(biāo)準(zhǔn)要求atexit( )至少支持注冊ATEXIT_MAX個函數(shù),而這個值至少是32。具體的值可以通過sysconf( )得到,參數(shù)是_SC_ATEXIT_MAX。

一個簡單的使用atexit( )的例子:

#include <stdio.h>
#include <stdlib.h>
void out(void) {
  printf("atexit( ) succeeded! \n");
}
int main(void) {
  if (atexit(out))
    fprintf(stderr, "atexit( ) failed! \n");
  return 0;
}

atexit( )成功時返回0,錯誤時返回-1.

SIGCHLD

當(dāng)一個進程子進程終止時,內(nèi)核會向其父進程發(fā)送SIGCHILD信號。
缺省情況下,會忽略此信號量,父進程也不會有任何的動作。
進程也可通過signal( )或者sigaction( )系統(tǒng)調(diào)用來有選擇的處理這個信號。

  • 子進程的終止和父進程是異步的,所以SIGCHILD信號可能會在任何時候產(chǎn)生,也會在任何時候被傳遞給父進程。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容