1. 程式人生 > >Linux下程序的總結(3)

Linux下程序的總結(3)

程序的控制

1.程序的建立

fork()函式

在一個程式碼段中建立一個新的子程序可以使用fork()函式。

1.fork()函式以父程序為模板創建出了一個子程序,但是父子程序程式碼共享,資料獨有一份。也就是分配新的記憶體塊和核心資料結構。然後父程序的部分資料拷貝到了子程序。

2.fork()函式的返回值是pid > 0,子程序的返回值是 == 0的。

3.fork()創建出一個子程序後,到底是子程序先執行還是父程序先執行。這個優先順序不確定。比如說子程序 和 父程序 在一個多核心的cpu的執行時候可能會並行執行。

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

int main()
{
pid_t pid;
printf("Before: pid = %d \n" ,getpid());
pid = fork();
printf("After The fork () pid = %d, return pid = %d \n", pid,getpid());
return 0;
}

在這裡插入圖片描述

分析以上程式碼可以知道在fork()函式之前pid是3196,執行fork()函式之後,子程序複製一份父程序的程式碼。但是子程序只執行,fork()後的程式碼段。第二行程式碼是父程序的程式碼結果。可以見得,fork()返回值是3197這是一個大於零的數。說明這是子程序返回的pid。第三行程式碼是子程序的程式碼段。可以見得,fork()返回值是0,說明這是該程序本身就是一個子程序。

特殊的vfork()函式

vfork()函式,子程序複製父程序的程式碼段。vfork()子程序和父程序共享地址空間,而fork()函式的子程序和父程序兩份地址空間。

在這裡插入圖片描述

/* This is a programe for Vfork*/

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("Firstly , The val is 100 \n");
int pid = vfork();
int val;
if(pid == 0)
{
 val = 200;
printf("This is child ! : pid = %d, getpid() :%d, val = %d \n", pid,getpid(),val);
exit(0);
}
else if (pid > 0)
{
printf("this is parent ! : pid = %d , getpid() = %d, val = %d \n ",pid,getpid(),val);
sleep(1);
}
return 0;
}

在這裡插入圖片描述

由以上程式碼可以得到,在子程序中修改了val的值,對於父程序來說它也被改變了。在子程序中val被賦值了200。在子程序結束的時候,父程序的val也被修改成了200。

vfork()建立過程

1.vfork也是建立一個子程序。子程序沒有退出或者執行其他程式,父程序是阻塞的。也就意味著子程序先執行。子程序沒有執行完成時,父程序暫時掛起。子程序退出之後父程序才能執行。##子程序不能在main()函式return 0 之後推出。

2.子程序先執行的原因是,創建出的子程序大多數的時候都是為了讓它執行其他的程式。

3.父程序阻塞的原因,vfork創建出的子程序,父子程序是公用一塊虛擬的記憶體空間的。

4.vfork設計出來的目的就是為了創建出一個子程序,然後直接執行其他的程式。而不是重新給子程序開闢新的空間,更新它自己的地址空間和頁表。

自從fork函式更新了寫實拷貝技術後,就被淘汰了。

2.程序的終止

當一個程式執行結束後需要退出了一般有3中退出的方式。

1.在main()函式當中使用return 0退出後程序結束。

2.exit(0)函式溫和的退出程式。

3._exit(0)函式暴力退出程式。

退出程式會後的返回值表明了它的狀態。如exit(int _status)表明狀態。公有3種狀態。

1.正常執行完畢,結果符合預期

2.正常執行完畢,但是結果不符合預期

3.異常退出,(如:段錯誤),根本就沒有有return ,其返回標準不能當做評判標準。

在這裡插入圖片描述

現在我們通過程式來看一看 exit(0) 和 _exit(0)有什麼不同?

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
printf("Hello ");
sleep(5);
printf("world!");
exit(0);
//_exit(0);
}

分別執行以上程式碼。得出以下結果

在這裡插入圖片描述

在這裡插入圖片描述
exit(0)會先把緩衝區的東西輸出後,然後再讓程式退出。
_exit(0)忽視緩衝區直接退出,不將緩衝區的東西打印出來。

3.程序的等待

一個程序退出之後,需要儲存自己的退出原因,因此不會釋放自己的所有資源。而父程序會等待著子程序的退出原因,然後結束自己的程序,釋放自己的所有資源。而如果父程序始終不接收這個子程序的退出原因,那麼子程序就會變成殭屍程序。造成記憶體洩漏,也是資源洩露。為了防止子程序變成殭屍程序,父程序就要關注並且管理子程序的退出狀態。

父程序如何管理子程序的退出狀態?

怎樣關注子程序的退出狀態?

在Linux下有一個wait()方法。

程序的等待就是等待子程序的狀態改變,獲取子程序的退出狀態碼,允許系統釋放子程序的所有資源,這時候子程序的所有資源會釋放掉。

程序等待能夠有效地避免殭屍程序的產生。

使用 pid_t wait (int *status)

#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
int main()
{
int pid = fork();
if(pid < 0)
{
exit(-1);
}

else if( pid == 0)

{
sleep (3);
exit(0);
}
//wait 函式的目的是為了等待任意一個子程序的退出
// 因為wait()是一個阻塞型的函式碼,如果沒有函式退出,他就一直等待,只到有子程序退出。如果wait(NULL)時則表明不關心退出狀態。

pid_t id 
if((id = wait(NULL)) <0)
{
perror("wait error");
}
printf ("child %d , exit :%d \n " ,id,pid);
return 0;
}

使用 pid_t waitpid( pid _t pid,int *status,int options)

當這個函式正常返回的時候,就會收集到子程序的程序ID。如果設定了選項WNOHANG,而除錯用的waitpid發現沒有退出的子程序可以手機,則返回0。如果調用出錯了,則返回-1,這時候errno會被設定成對應的值以指示錯誤所在

引數分析

pid :pid = -1等待任意一個子程序。此時與wait等效

pid > 0 表示等待的程序ID與pid相等的子程序

status :WIFEXITED(status):若為正常終止返回子程序返回狀態,則為真。(檢視程序是否正常退出)。
WEXITSTATUS(status):若WIFEXITED非零,提取子程序退出碼(檢視程序的退出碼)。

options:
WNOHANG :若pid指定的子程序沒有結束,則waitpid()函式返回0,不予以等待。若正當結束則返回該子程序ID。