fork, vfork以及return, exit

exit函數在頭文件stdlib.h中。

exit(0):正常運行程序並退出程序;

exit(1):非正常運行導致退出程序;

return():返回函數,若在main主函數中,則會退出函數並返回一值,可以寫爲return(0),或return 0。

詳細說:

1. return返回函數值,是關鍵字;exit是一個函數。

2. return是語言級別的,它表示了調用堆棧的返回;而exit是系統調用級別的,它表示了一個進程的結束。
3. return是函數的退出(返回);exit是進程的退出。

4. return是C語言提供的,exit是操作系統提供的(或者函數庫中給出的)。

5. return用於結束一個函數的執行,將函數的執行信息傳出個其他調用函數使用;exit函數是退出應用程序,刪除進程使用的內存空間,並將應用程序的一個狀態返回給OS,這個狀態標識了應用程序的一些運行信息,這個信息和機器和操作系統有關,一般是 0 爲正常退出,非0 爲非正常退出。

6. 非主函數中調用return和exit效果很明顯,但是在main函數中調用return和exit的現象就很模糊,多數情況下現象都是一致的。

下面是幾個例子:

1.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  pid_t pid;
  int count=0;

  pid=vfork();
  if(pid==0)
  {
    printf("child: count=%d\n",count);
    printf("child: getpid=%d\n",getpid());
    count=1;
    printf("child: count=%d\n",count);
    // return 0;//會出現段錯誤
    exit(0); //ok
  }
  else
  {
    printf("\nfather: pid=%d\n",pid);
    printf("father: count=%d\n",count);
  }
  return(0);
}

運行結果

[root@localhost part1_linux]# gcc fork2.c 
[root@localhost part1_linux]# ./a.out 
child: count=0
child: getpid=9911
child: count=1

father: pid=9911
father: count=1

運行結果說明:vfrok時父、子進程共享數據段,fork時是進行拷貝。如果,vfork子進程中,使用return返回時,出現段錯誤,結果如下:

[root@localhost part1_linux]# gcc fork2.c 
[root@localhost part1_linux]# ./a.out 
child: count=0
child: getpid=10864
child: count=1

father: pid=10864
father: count=0
段錯誤
2. 爲什麼執行結果子進程打印出來 我的父親是id:1,與父進程id不同
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
	int i=0;
	pid_t pid;
	printf("還沒創建子進程\n");
	i++;
	pid = fork();
	if(pid==-1)
	{
	  printf("fork error!\n");
	}
	else if(pid==0)
	{
	  i++;
	  printf("我是子進程,id%d\n",getpid());
  	  printf("我的父親是id:%d\n",getppid());
   	  printf("-----i=%d-----\n",i);
	}
	else
	{
	  i++;
	  printf("我是父進程,id:%d\n",getpid());
	  printf("-----i=%d-----\n",i);
	}
	exit(0);
}
子進程在打印第一句時,父進程也在打印第一句,但是子進程在執行第二句時,父進程已經直接over了(這只是個簡單的說法,實際過程可能並不如此,我要說的是,父進程先於子進程的打印語句之前就結束)。因此此時的子進程成了孤兒進程,會被init也就是1號進程領養,成爲init的子進程。 爲了避免這樣的情況,父進程最後可以執行wait來等待子進程的返回。
3. 用vfork()創建子進程,執行後程序一直不斷地重複運行,不斷創建子進程,結尾用exit(0)代替return(0)後問題就能解決
return 0在一個函數中是正常的返回過程,它會使得程序返回到函數被調用處,回覆之前的執行流程,return 語句不會被執行。而exit 一般是在任意位置和使用的,執行到exit 0時,整個進程就over了(這也是爲什麼在多線程程序中不要隨意使用exit的原因),用來使程序退出運行,一般用來處理(不可挽回的)錯誤狀態。
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
  int i=0;
  pid_t pid;
  printf("還沒創建子進程\n");
  i++;
  pid = vfork();
  if(pid==-1)
  {
    printf("fork error!\n");
  }
  else if(pid==0)
  {
    i++;
    printf("我是子進程,id%d\n",getpid());
    printf("我的父親是id:%d\n",getppid());
    printf("-----i=%d-----\n",i);
  }
  else
  {
    i++;
    printf("我是父進程,id:%d\n",getpid());
    printf("-----i=%d-----\n",i);
  }
  return(0);
}

1. 但是 vfork 並不將父進程的地址空間完全複製到子進程中,因爲子進程會立即調用 exec(或exit),於

是也就不會存訪該地址空間。不過在子進程調用 e x e c或e x i t之前,它在父進程的空間中運行。 這種工作方式在某些 U N I X的頁式虛存實現中提高了效率

2. vfork和fork之間的另一個區別是: vfork保證子進程先運行,在它調用 exec或exit之後父進 程纔可能被調度運行。 (如果在調用這兩個函數之前子進程依賴於父進程的進一步動作,則會導致死鎖。)

    1. #include <sys/types.h>  
      #include "ourhdr.h"  
        
      int glob = 6;  
      char buf[] = "a write to stdout";  
        
      int main()  
      {  
          int var;  
          pid_t pid;  
          var = 88;  
          if( write(STDOUT_FILENO , buf , sizeof(buf) - 1) != sizeof(buf) - 1)  
            err_sys("write error!\n");  
          printf("before fork\n");  
          fflush(stdout);  
        
          if( (pid = fork()) < 0)  
            err_sys("fork error");  
          else if( pid == 0 ) {   
              glob ++ ;  
              var ++;  
          }else  
            sleep(2);  
            
          printf("pid = %d , glob = %d , var = %d\n", getpid() , glob , var);  
          return 0;  
      }  

運行後輸出結果:

a write to stdoutbefore forkpid = 11058 , glob = 7 , var = 89pid = 11057 , glob = 6 , var = 88

這個程序的結果是很明顯的"正確",因爲fork 產生的子進程 複製了父進程的資源 , 但是他們是在不同的地址空間運行!

再看vfork的例子:摘自《unix環境高級編程》

#include <sys/types.h>  
#include "ourhdr.h"  
  
int glob = 6;  
int main()  
{  
    int var;  
    pid_t pid;  
    var = 88;  
    printf("before vfork\n");  
    if( (pid = vfork()) < 0)  
      err_sys("vfork error");  
    else if( pid == 0 ){  
        glob ++;  
        var ++;  
        _exit(0);  
    }  
  
    printf("pid = %d , glob = %d , var = %d \n" , getpid(), glob , var);  
    exit(0);  
}  


這個程序執行的結果請看了::

before vforkpid = 11213 , glob = 7 , var = 89 

vfork出的子進程居然改變了父進程中的變量值!

原因就是前面說的:在子進程調用 e x e c或e x i t之前,它在父進程的空間中運行。這種情況就像是一個線程的行爲了

PS:子進程爲什麼使用_exit退出

_exit並不執行標準I/O緩存的刷新操作。如果用exit而不是_exit,則該程序的輸出是:$ a.outbefore vfork從中可見,父進程 printf的輸出消失了。其原因是子進程調用了 exit,它刷新開關閉了所有標準I / O流,這包括標準輸出。雖然這是由子進程執行的,但卻是在父進程的地址空間中進行的,所以所有受到影響的標準 I/O FILE對象都是在父進程中的。當父進程調用 printf時,標準輸出已

被關閉了,於是printf返回-1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章