一 linux下進程的理解:
linux環境下一個進程在內存中有三部分數據:數據段 堆棧段和代碼段
代碼段:就是存放程序代碼的數據,若是有數個進程運行一個程序,那麼他們就可使用同一個代碼段
堆棧段:存放的是子程序的返回地址 參數以及程序的局部變量
數據段:存放程序的全局變量 常數以及動態數據分配的數據空間
系統若是同時運行數個相同的程序,他們之間就不能使用同一個堆棧段和數據段,可是可使用同一個代碼段
二 fork函數的使用
linux環境下產生新的進程的系統調用是fork函數,一個進程在運行的時候,使用了fork,就會產生另外一個進程
例子:
#include <iostream>
using namespace std;
int main(){
int i;
if(0==fork()){
for(i=1;i<1000;i++)
cout<<"this is child process"<<endl;
}
else{
for(i=1;i<1000;i++)
cout<<"this is parent process"<<endl;
}
}
編譯運行會在屏幕上交替出現子進程和父進程各打印出的一千條信息,若是程序還在運行使用ps命令能夠查看獲得兩個它在運行
在linux環境下,一個程序一調用fork函數,系統就會產生信的進程,而且爲新的進程準備程序段 堆棧段 數據段等。由於他們的程序是相同的,因此新產生的進程和舊進程使用同一個代碼段;對於數據段和堆棧段,系統會複製一份給新進程,父進程的全部數據均可以給子進程,而且他們的運行是分開的,相互之間沒有影響,也就是說他們不共享任何數據。若是父進程和子進程須要共享數據,那麼須要另外一套函數來完成,之後會詳細說明的。
fork完後會產生子進程,對於父進程而言,fork函數返回的是子進程的進程號,對於子進程,fork返回的是零,所以在程序中,咱們只要判斷fork的返回值,就能判斷是在父進程中仍是子進程中
fork函數執行一次,產生一個新進成,複製數據段 堆棧段,可是若是一個大程序在運行的時候,fork的時候複製數據段和堆棧段會不會開銷很大呢?linux自有解決的方法:通常CPU都是以頁爲單位分配空間的,不管是數據段仍是堆棧段都是由不少頁組成的,當實際執行fork的時候,物理空間上兩個進程的數據段和堆棧段仍是共享的,邏輯上是分開的,只有當一個進程寫某個數據的時候,這時兩個進程之間的數據纔有了區別,系統會將有區別的頁從物理上分開,而其餘的不動,從而使系統在空間上的開銷達到最小。
三 一個進程啓動一個程序的執行
在linux環境下,一個進程能夠啓動一個程序的執行可使用exec類的函數來完成,注意是exec類的函數,這個類中有不少exec函數。
一個進程一旦調用了exec類的函數,它自己就死了,它的代碼段會被替換成新的程序代碼,而且廢棄原油的數據段和堆棧段,從新分配信的數據段和堆棧段,惟一留下的就是進程號,對於系統而言,仍是同一個進程,不過這個進程已是另外一個程序了。若是一個程序想啓動另外一個程序的執行可是繼續運行本身的話,須要結合fork函數和exec函數一塊使用
例子:
char command[256];
int main(){
int rtn;
while(1){
cout<<">"<<endl;
fgets(command,256,cin);
command[strlen(command)-1]=0;
if(0==fork()){
execlp(command,command);
cerr<<command<<endl;
exit(cerr);
}
else{
wait(&rtn);
cout<<"child process return "<<rtn<<endl;
}
}
reutrn 0;
}
父進程和子進程都使用相同的映像,該函數和普通函數的不一樣之處是函數若是執行成功會返回來兩次,在父進程中返回子進程的pid,子進程中返回0函數返回成功後,父進程和子進程都在fork函數執行後繼續執行,若是調用函數不成功則返回值是-1
wait函數保證父進程運行完後等待子進程退出才退出,不然父進程結束了,子進程還在運行
好了,linux下的多進程編程就這麼點內容,其實讓兩個進程獨立運行很容易,關鍵的難點是父進程和子進程共享數據進行通訊。
例子:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#define FAC_N 65535
void big_loop(int n);
void input_information();
int main(){
pid_t pid;
pid=fork();
switch(pid){
case -1:
perror("fork\n");
break;
case 0:
big_loop(FAC_N);
printf("PID:%d\n",getpid());
break;
default:
input_information();
printf("PID:%d\n",getpid());
break;
}
wait();
exit(0);
}
void big_loop(int n){
int i;
for(i=0;i<n;i++){
switch(i%4){
case 0:
putchar("-");
break;
case 1:
putchar('/');
break;
case 2:
putchar('|');
break;
case 3:
putchar('\\');
break;
}
putchar('\b');
}
} linux
void input_information(){
int n_table[4],i;
for(i=0;i<4;i++){
printf("Number %d:",i);
scanf("%d",&n_table[i]);
}
printf("Number1\tNumber2\tNumber3\tNumber4\n");
printf("%d\t%d\t%d\t%d\n", n_table[0], n_table[1], n_table[2], n_table[3]);
}ios