您的位置:首页 > 运维架构 > Linux

linux 多进程编程基础

2015-05-22 00:00 183 查看
一 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');
}
}

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]);
}

转自:http://jiaojiaoni.com/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息