一 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