天天看點

程序建立函數fork()和vfork()

Linux下使用fork()建立一個新的程序,該函數不需要參數,傳回值是一個程序id。對于不同的對象,分别是:建立的子程序id(傳回給父程序),0(傳回給建立的子程序)或者-1(子程序建立失敗,傳回給父程序)。建立的新程序在得到一個新的程序id之後,将拷貝父程序空間中内容至子程序,包括父程序的資料段和堆棧段,并且子程序和父程序共享代碼段。vfork()和fork()則不一樣,父子程序共享位址空間,包括代碼段、資料段和堆棧段。子程序對于共享資料的修稿會影響到父程序,而且子程序一定比父程序先運作完,父程序調用vfork()函數後等待子程序運作完成再接着運作。

接下來,使用fork()建立一個子程序,并且在子程序中顯示父程序的程序号和子程序的程序id,在父程序中顯示出父程序的程序id和子程序的程序id。

#include<iostream>
#include<stdlib.h>
#include<unistd.h>
using namespace std;

int main(){
	pid_t pid;
	pid = fork();
	if(pid < 0){
		cout << "Create fail!" << endl;
		exit(0);
	}
	else if(pid == 0){
		cout << "This is the child process! PID is: " << getpid() << endl;
		cout << "The parent process id is: " << getppid() << endl;
	}
	else{
		cout << "This is the parent process! PID is: " << getpid() << endl;
		cout << "The child process id is: " << pid << endl;
	}
	return 0;
}
           

編譯并運作:

程式建立函數fork()和vfork()

發現在子程序中,由函數getppid()傳回的程序号與對應的父程序的程序号并不一緻。在父程序中,能夠正确傳回子程序的程序id。利用ps指令檢視子程序傳回的父程序id對應的程序:upstart,後來在部落格https://blog.csdn.net/Leafage_M/article/ details/70273624中看到一個很清楚詳細的解釋。shell中先列印出父程序的程序資訊,然後再列印出子程序的程序資訊,那麼就相當于父程序完成之後,被殺死了,然後再執行的是子程序的資訊,而此時子程序就成了孤兒程序,它被upstart這個程序收養了,此時調用getppid()傳回的當然就是upstart的pid了。對于這種問題的解決方法之一就是在父程序的執行語句中加入延時挂起sleep()操作,讓父程序不至于太快銷毀。

之前說到fork()和vfork()的差別,編寫兩個執行個體進行驗證:

#include<iostream>
#include<stdlib.h>
#include<unistd.h>
using namespace std;

int global; //全局變量(資料段中)
int main(){
	pid_t pid;
	int stack = 1;  //局部變量(棧中)
	int* heap;  //局部變量(堆中)
	heap = (int* )malloc(sizeof(int));
	*heap = 2;
	pid = fork();
	if(pid < 0){
		cout << "Fail to fork!" << endl;
		exit(1);
	}
	else if(pid == 0){
		global ++;
		stack ++;
		(*heap)++;
		cout << "This is the child process! PID is: " << getpid() << endl;
		cout << "The parent process id is: " << getppid() << endl;
		cout << "The child data: " << global << " " << stack << " " <<  *heap << endl;
		exit(0);
	}
	else{   
		sleep(3);  
		cout << "This is the parent process! PID is: " << getpid() << endl;
		cout << "The child process id is: " << pid << endl;
		cout << "The parent data: " << global << " " << stack << " " << *heap << endl;
		exit(0);
	}
	return 0;
}
           

之後再将上面程式中fork()函數改為vfork(),并将延時語句注釋掉。編譯和運作結果對比:

程式建立函數fork()和vfork()

可以看出,fork()建立的子程序中三個變量都發生變化時,父程序雖然在子程序之後才通路資料,但是子程序中對變量的修改并不影響父程序的程序環境。但是vfork()則不一樣。再看程序id,在加入sleep()函數之後,fork()函數建立的子程序也能夠正常傳回父程序的id了。而在vfork()函數建立的子程序中,父子程序的傳回的父程序、子程序id皆一緻。

fork()函數在兩種情況下容易出錯:系統中已經有很多程序,調用fork()函數的使用者程序過多。

繼續閱讀