1. 进程
进程是程序的一个执行实例,指令+执行上下文 = 进程。
每个进程被分配给一个进程号作为唯一标识,系统维护一个进程表,每个表项保存了一个进程的相关信息。32位CPU的寻址范围是4G所以通常一个进程的逻辑地址空间是4G,其中有1G是属于内核代码段,其余属于用户代码段和数据段。
2. 进程的启动和创建
2.1 system 函数启动线程
2.2 exec 系列函数 :代替当前执行的进程
2.3 fork函数:复制新进程
当在进程A中执行系统fork函数时,进程表会创建一个新的表项,拥有一个唯一的进程ID,也就是进程号(PID),进程表项的其他值大部分与进程A的相同,具体说来,就是新进程B和A共享代码段,并且B将A的数据空间,堆栈等复制一份 ,然后从A创建B的地方开始运行。
从代码的角度看,创建一个新进程的fork函数原型为:
pid_t pid = fork(void);
fork函数被包含在unistd.h文件中,pid_t 是进程号类型,通常是32位整数,fork函数的返回值,如果是在被创建的子进程中进行检测,则返回值为0,若在父进程中检测,则为子进程id,若创建失败则返回负数。
有如下代码段:
#include <stdio.h> #include <unistd.h> using namespace std; int main(int argc, char* argv[]) { printf("before fork...\n"); int iTestValue = 0; pid_t id = fork(); if (id < 0) { printf("fork error..."); } else if (id == 0) { iTestValue ++; printf("in child process...|%d\n", iTestValue); printf("in child process...|%d\n", getpid()); printf("in child process...|%d\n", getppid()); } else { iTestValue ++; printf("in parent process...|%d\n", iTestValue); printf("in parent process...|%d\n", getpid()); printf("in parent process...|%d\n", getppid()); } printf("after fork...\n"); return 0; }
程序输出:
其中函数getpid()返回当前进程id,getppid()返回当前进程的父进程id,父进程创建子进程和创建后两个进程执行的过程如下图所示:
另外,fork失败,会返回负数,这通常是由于系统作了最大进程数目限制CHILD_MAX,相应的errno(全局变量,需#include<errno.h>)是EAGAIN. 如果没有足够的空间资源,errno会是ENOMEM,关于系统的最大进程数目限制:
3. 进程等待
头文件wait.h中的函数wait方法会导致父进程阻塞等待子进程执行完毕。这个调用会返回该子进程的PID。如果有错误,返回-1,错误码保存在errno中。函数原型为:
pid_t wait(int* stat_loc);
用宏WIFEXITED(stat_loc)判断子进程是否正常退出;
用宏WEXITSTATUS(stat_loc)返回子进程的退出码。
对上述测试代码修改为:
#include <errno.h> #include <wait.h> #include <stdio.h> #include <unistd.h> using namespace std; int main(int argc, char* argv[]) { printf("before fork...\n"); int iTestValue = 0; pid_t id = fork(); if (id < 0) { printf("fork error..."); } else if (id == 0) { iTestValue ++; printf("in child process...|%d\n", iTestValue); printf("in child process...|%d\n", getpid()); printf("in child process...|%d\n", getppid()); } else { int stat_val; pid_t child_id = wait(&stat_val); if (WIFEXITED(stat_val)) { printf("exit code:|%d\n", WEXITSTATUS(stat_val)); iTestValue ++; printf("in parent process...|%d\n", iTestValue); printf("in parent process...|%d\n", getpid()); printf("in parent process...|%d\n", getppid()); } } printf("errno:|%d\n", errno); printf("after fork...\n"); return 0; }
输出:
可以看出,wait方法使得父进程创建了子进程之后便一直等待直到子进程执行完毕才继续执行。