什么是一个进程?进程这个概念是针对系统而不是针对用户的,对用户来说,他面对的概念是程序。当用户敲入命令执行一个程序的时候,对系统而言,它将启动一个进程。但和程序不同的是,在这个进程中,系统可能需要再启动一个或多个进程来完成独立的多个任务。多进程编程的主要内容包括进程控制和进程间通信,在了解这些之前,我们先要简单知道进程的结构。
1. Linux下进程的结构
Linux下一个进程在内存里有三部分的数据,就是"代码段"、"堆栈段"和"数据段"。其实学过汇编语言的人一定知道,一般的CPU都有上述三种段寄存器,以方便操作系统的运行。这三个部分也是构成一个完整的执行序列的必要的部分。
"代码段",顾名思义,就是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。"堆栈段"存放的就是子程序的返回地址、子程序的参数以及程序的局部变量。而数据段则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。这其中有许多细节问题,这里限于篇幅就不多介绍了。系统如果同时运行数个相同的程序,它们之间就不能使用同一个堆栈段和数据段。
2.Linux下的进程控制
在传统的Unix环境下,有两个基本的操作用于创建和修改进程:函数fork( )用来创建一个新的进程,该进程几乎是当前进程的一个完全拷贝;函数族exec( )用来启动另外的进程以取代当前运行的进程。Linux的进程控制和传统的Unix进程控制基本一致,只在一些细节的地方有些区别,例如在Linux系统中调用vfork和fork完全相同,而在有些版本的Unix系统中,vfork调用有不同的功能。由于这些差别几乎不影响我们大多数的编程,在这里我们不予考虑。
3.fork() 函数
fork在英文中是"分叉"的意思。为什么取这个名字呢?因为一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就"分叉"了,所以这个名字取得很形象。返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。
fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了改应用程序的两个副本。
实例:
#include <unistd.h>
#include <stdio.h>
int main ()
{
pid_t fpid; //fpid表示fork函数返回的值
fpid=fork();
if (fpid < 0) //提示进入出错信息
{
printf("error in fork!\n");
}
else if (fpid == 0) //如果fork()返回0,则说明在子进程中;
{
printf("i am the child process, child pid is %d\n",getpid());//打印子进程的ID号
printf("我是儿子!\n"); //对某些人来说中文看着更直白。
sleep(2);
}
else //如果返回值大于零(实际上是子进程的ID号),则说明在父进程中;
{ //分别打印子进程、父进程ID号
printf("i am the parent process, child pid is %d,parent pid is %d\n",pid,getpid());
printf("我是父亲!\n");
sleep(2);
}
return 0;
}
程序运行结果:
为了更加清楚的了解其工作时的状态,这里让父子进程都休眠一段时间,再利用ps –e命令查看当前的父进程和子进程:
else if (fpid == 0) //如果fork()返回0,则说明在子进程中;
{
printf("i am the child process, child pid is %d\n",getpid());
printf("我是儿子!\n");
sleep(50);//休眠一段时间,便于查看当前进程
}
else
{
printf("i am the parent process, child pid is %d,parent pid is %d\n",pid,getpid());
printf("我是父亲!\n");
sleep(50);//休眠等待
}
ps-e查看结果:
等到休眠结束后,再次查看当前运行的进程,发现两个fork进程都退出了: