linux系統編程:進程式控制制(fork),linuxfork
在linux中,用fork來建立一個子進程,該函數有如下特點:
1)執行一次,返回2次,它在父進程中的傳回值是子進程的 PID,在子進程中的傳回值是 0。子進程想要獲得父進程的 PID 需要調用 getppid 函數。
2)產生的子進程會複製fork函數之後的代碼
3)父子進程的全域變數和局部變數,是不共用的
4)子進程會繼承父進程的環境狀態
/*================================================================* Copyright (C) 2018 . All rights reserved.* * 檔案名稱:fork.c* 創 建 者:ghostwu(吳華)* 建立日期:2018年01月12日* 描 述:fork基本使用*================================================================*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>int count = 10;int main(int argc, char *argv[]){ pid_t pid; int var = 5; printf( "----fork之前------,當前進程id=%d\n", getpid() ); pid = fork(); printf( "----fork之後------\n" ); if( pid < 0 ) { perror( "fork" ); exit( -1 ); }else if( pid == 0 ) { //子進程 var++; count++; }else { sleep( 3 ); } printf( "fork傳回值pid=%d, 當前進程pid=%d, count=%d, var=%d\n", pid, getpid(), count, var ); return 0;}
上例,我們可以看出:
1)子進程並不會輸出"fork之前“這段代碼,因為子進程拷貝的是fork之後的代碼
2)子進程對變數操作之後,對父進程的變數沒有任何影響,他們是2個不同的副本
3)標準輸出是行緩衝模式:遇到分行符號時進行重新整理、緩衝區滿了的時候重新整理、強制重新整理(fflush);而標準輸出(stdout)是行緩衝,因為涉及到終端裝置;
把這個例子的輸出方式,再改一下:
這裡,你會發現,多了兩個輸出( "fork之前" ),因為,採用管道重新導向輸出之後,IO操作就變成了全緩衝模式,子進程產生的時候是會複製父進程的緩衝區的資料的,所以子進程重新整理緩衝區的時候子進程也會將從父進程緩衝區中複製到的內容重新整理出來。因此,在使用 fork產生子進程之前一定要使用 fflush(NULL) 重新整理所有緩衝區!
/*================================================================* Copyright (C) 2018 . All rights reserved.* * 檔案名稱:fork.c* 創 建 者:ghostwu(吳華)* 建立日期:2018年01月12日* 描 述:fork基本使用*================================================================*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>int count = 10;int main(int argc, char *argv[]){ pid_t pid; int var = 5; printf( "----fork之前------,當前進程id=%d\n", getpid() ); fflush( NULL ); pid = fork(); printf( "----fork之後------\n" ); if( pid < 0 ) { perror( "fork" ); exit( -1 ); }else if( pid == 0 ) { //子進程 var++; count++; }else { sleep( 3 ); } printf( "fork傳回值pid=%d, 當前進程pid=%d, count=%d, var=%d\n", pid, getpid(), count, var ); return 0;}View Code
這個時候,就不會有兩個("fork之前" ),因為fork產生子進程之前,已經把父進程緩衝區的資料重新整理到核心緩衝區,不在標準IO的緩衝區
子進程如果比父進程先結束,那麼子進程會變成殭屍進程。
因為:它們必須得等待父進程為其“收屍”才能徹底釋放,如果父進程先結束了,那麼這些子進程的父進程會變成 1 號 init 進程,當這些子進程運行結束時會變成殭屍進程,然後 1 號 init 進程就會及時為它們收屍
/*================================================================* Copyright (C) 2018 . All rights reserved.* * 檔案名稱:fork3.c* 創 建 者:ghostwu(吳華)* 建立日期:2018年01月12日* 描 述:*================================================================*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(int argc, char *argv[]){ pid_t pid; int i = 0; for( i = 0 ; i < 10; i++ ) { pid = fork(); if( pid < 0 ) { perror( "fork()" ); exit( -1 ); }else if( pid == 0 ) { printf( "[pid]=%d\n", getpid() ); exit( 0 ); } } sleep( 10 ); return 0;}View Code
父進程如果比子進程先結束,那麼子進程會變成孤兒進程
所有子進程的父進程都變成了 1 號 init 進程
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main(int argc, char *argv[]){ pid_t pid; int i = 0; for( i = 0 ; i < 10; i++ ) { pid = fork(); if( pid < 0 ) { perror( "fork()" ); exit( -1 ); }else if( pid == 0 ) { sleep( 10 ); printf( "[pid]=%d\n", getpid() ); exit( 0 ); } } return 0;}View Code