一、什么是进程?

进程包含存储在文件中的一组指令,该文件被读入内存并执行。正在执行的每个唯一的实例被称为进程,并且给它唯一一个标识,成为进程ID,它由操作系统确定。比如你在电脑中同时打开两个QQ,那么这两个程序就叫做进程,而且有两个不同的ID号。


二、进程如何创建?

被称为子进程的新进程由父进程的已存在的进程通过调用fork函数创建。

pid=fork();//fork函数回传给pid的值是新进程的ID,数据类型为pid_t,属于int型。

子进程被创建为父进程的一个副本。

fork函数在成功时给父进程和它创建的子进程都返回一个值:它把新创建的子进程的进程ID返回给父进程,给新创建的子进程返回;如果调用不成功,则进给父进程返回-1,并且不创建子进程。

注意:要使用fork函数必须包含unistd.h头文件。


三、进程如何退出?

子进程可以在它的父进程退出之前或者之后退出,但是通常倾向于在父进程退出之前先退出它所有的子进程。子进程在它的父进程退出之前,父进程可以获得子进程的退出状态,从而可以确定该子进程是否成功退出。

父进程可以通过调用定义在头文件wait.h中的wait函数获得子进程的退出状态。

wait函数返回退出的子进程的进程ID或者0(不存在子进程),在程序片段中被保存在pid中。

比如下面一段程序:

#include<wait.h>
...
pid_t pid;
int status;
...
/*Pause until a child process exits*/
pid=wait(&status);
if(pid>0)
        printf("pid %d status %d\n",pid,WEXITSTATUS(status));
//使用宏调用  WEXITSTATUS可以从变量status中提取出代码


四、怎样让进程中执行另一个程序?

如果想创建一个与父进程实现不同功能的新进程,首先需要用fork函数创建一个新进程,然后用实现预期操作的新指令替换与新进程相关的指令。这就需要用到execl函数,如果此函数调用成功,现有的进程指令被新进程的指令代替,原始指令不复存在。

一般进程从扩展名为.exe的可执行文件中读入这些指令,命令行参数可从execl函数中传入进程指令中。看下面的一段程序:

pid

#include<unistd.h>
...
pid_t pid;
...
pid=fork();
if (pid==0)
        execl("newprog.exe","newprog.exe",NULL);
printf("Parent process after if statement\n");
//如果子进程正在执行(pid==0),execl函数执行,用从可执行文件newprog.exe中获得的指令代替原有的指令,由于原有的指令不复存在,故子进程中不执行printf语句,而执行文件newprog.exe中的任何指令。
...


五、进程之间是如何通信的?
已知进程间通信的最古老形式为管道,它由两个文件描述符构成,一个为读打开,另一个为写打开。管道由pipe函数创建,因为并非所有的操作系统都支持全双工管道(能同时向两个方向发送信息的管道,半双工以此类推),全双工管道可以用两个半双工管道模拟,其中一个用作读,另一个用作写。

管道怎么用?

还是看一段程序吧:


#include<unistd.h>
...
int filedes[2];
char buffer[30];
...
if (pipe(filedes)<0)
{
    printf("Error Creating The Pipe\n");
    ...
}
...
//关闭读文件符,然后将字符串“buffer contents”写入写文件描述符。
if(close(filedes[0])<0)
    printf("Error Closing The Read File Descriptor\n");
strcpy(buffer,"Buffer Contents");
if(write(filedes[1],buffer,strlen(buffer))<0)
    printf("Error Writing To The Write File Descriptor\n");
...
//关闭写文件描述符,然后从读文件描述符中读去数据
if(close(filedes[1])<0)
    printf("Error Closing The Write File Descriptor\n");
if(read(filedes[0],buffer,sizeof(buffer))<0)
    printf("Error Reading From The Road File Descriptor\n");
....

最后举个实际应用中的一个简单的例子吧:

当你用浏览器上网的时候,打开的一个一个标签页就是一个一个的子进程,而浏览器是哥父进程,当你没有直接关闭浏览器的时候,出来选项“是否关闭所有的标签页”,你点击是的时候,其实是浏览器向每一个标签页发送了消息,直到全部关闭,而你的操作,每一个标签页是无法直接接收到的。