#include <unistd.h>
pid_t getpid(void);
Returns: PRocess ID of calling process
pid_t getppid(void);
Returns: parent process ID of calling process
uid_t getuid(void);
Returns: real user ID of calling process
uid_t geteuid(void);
Returns: effective user ID of calling process
gid_t getgid(void);
Returns: real group ID of calling process
gid_t getegid(void);
Returns: effective group ID of calling process
- 父進程等待子進程完成。這種情況下,父進程無需對其描述符做任何處理。
- 父進程和子進程各自執行不同的程序段。這種情況下,fork之后,父子進程各自它們不需要使用的文件描述符。
strlen和sizeof的區別:前者不包括null字節,一次函數調用;后者包括null字節,編譯時計算
除了文件描述符之外,父進程的很多其他屬性也由子進程繼承,包括:
- 實際用戶ID、實際組ID、有效用戶ID、有效組ID
- 附屬組ID
- 進程組ID
- 會話ID
- 控制終端
- SUID和SGID標志(stat結構的st_mode成員)
- 當前工作目錄
- 根目錄
- 文件模式創建屏蔽字umask
- 信號屏蔽和處理
- 對任一打開文件描述符的執行時關閉(close-on-exec)標志
- 環境
- 連接的共享存儲段
- 存儲映像
- 資源限制
- 是否繼承nice值由具體實現自行決定
父進程和子進程之間的區別具體如下:
- fork的返回值不同
- pid不同
- 這兩個進程的父進程不同
- 子進程的tms_utime、tms_stime、tms_cutime和tms_ustime的值設置為0
- 子進程不繼承父進程設置的文件鎖
- 子進程的未處理鬧鐘被清除
- 子進程的未處理信號集設置為空集
fork失敗的兩個主要原因:
- 系統中已經有了太多的進程
- 該實際用戶ID的進程總數超過了系統限制
fork有以下兩種用法:
- 一個父進程希望復制自己,使父進程和子進程同時執行不同的代碼段。這在網絡服務器中是常見的。
- 一個進程要執行一個不同的程序。這對shell是常見的情況。某些系統將fork+exec組合成一個操作spawn
- vfork函數用于創建一個新進程,而該新進程的目的是exec一個新程序,故不將父進程的地址空間完全復制到子進程中,因為子進程會立即調用exec(或exit),于是也就不會引用該地址空間。不管在子進程調用exec或exit之前,它在父進程的空間中運行。
- 另一個區別是vfork保證子進程先運行,在它調用exec或exit之后父進程才可能被調度運行。故如果在調用這兩個函數之前子進程依賴于父進程的進一步動作,則會導致死鎖。
正常終止
方式:
- 從main中執行return,等效于調用exit
- 調用exit函數,調用各終止處理程序,關閉標準I/O流,最后調用_exit函數
- 調用_exit或_Exit
- 進程的最后一個線程在其啟動例程執行return語句,該進程以終止狀態0返回
- 進程的最后一個線程調用pthread_exit,進程終止狀態總是0
異常終止
方式:
- 調用abort,它產生SIGABRT信號
- 當進程接收到某些信號時,信號可由進程自身(如調用abort函數)、其他進程或內核產生
- 最后一個線程對“取消”請求做出響應
注意:“退出狀態”(3個exit函數的參數或main的返回值)區別于“終止狀態”。在最后調用_exit時,內核將退出狀態轉換為終止狀態。
如果父進程在子進程之前終止,則稱子進程為孤兒進程
。子進程 ppid變為1,稱這些進程由init進程收養
。一個init進程收養的進程終止時,init會調用一個wait函數取得其終止狀態,防止它成為僵尸進程。
僵尸進程
zombie/defunct。#include <sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
Both return: process ID if OK, 0 (see later), or −1 on error
- 如果其所有子進程都還在運行,則阻塞
- 如果一個子進程終止,正等待其父進程獲取其終止狀態,則取得該子進程的終止狀態立即返回
- 如果它沒有任何子進程,則立即出錯返回
- waitpid有一選項,可使調用者不阻塞
- waitpid可以控制它所等待的進程
若statloc不是NULL,則終止進程的終止狀態就存放在它所指向的單元內。該整型狀態字由實現定義,其中某些位表示退出狀態(正常返回),其他位則指示信號編號(異常返回),有一位指示是否產生了core文件。
waitpid函數中的pid參數的解釋:
pid == -1,等待任一子進程,等價于wait函數pid > 0,等待pid等于該值的子進程pid == 0,等待組ID等于調用進程組ID的任一子進程pid < 0,等待組ID等于pid絕對值的任一子進程
waitpid函數中的options參數:WNOHANG(不阻塞)、WCONTINUED、WUNTRACED
如果一個進程fork一個子進程,但不要它等待子進程終止,也不希望子進程處于僵尸狀態直到父進程終止,實現這一要求的訣竅是調用fork兩次。
#include "apue.h"
#include <sys/wait.h>
int main(void)
{
pid_t pid;
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) { /* first child */
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid > 0)
exit(0); /* parent from second fork == first child */
/*
* We’re the second child; our parent becomes init as soon
* as our real parent calls exit() in the statement above.
* Here’s where we’d continue executing, knowing that when
* we’re done, init will reap our status.
*/
sleep(2);
printf("second child, parent pid = %ld/n", (long)getppid());
exit(0);
新聞熱點
疑難解答