1. 进程号:linux
每一个进程在被初始化的时候,系统都会为其分配一个惟一标识的进程id,称为进程号;shell
进程号的类型为pid_t,经过getpid()和getppid()能够获取当前进程号和当前进程的父进程的进程号;数据结构
2. 进程复制:函数
fork函数,是以父进程为蓝本复制一个新的子进程,包括复制代码段,数据段,堆栈段等,除了代码段,子进程会有本身的物理内存空间,其中的内容是和父进程的数据段,堆栈段是同样的,固然进程号是不同;spa
在linux下,fork函数是用写复制实现的。所谓写复制,只复制父进程的虚拟地址空间(数据结构),子进程并不会产生本身的物理内存空间,直到父进程或者子进程中有对某个段的写行为的时候,再为子进程建立独立的物理内存控制。写复制的目的是为了提供建立进程的效率;code
fork函数在父进程中调用一次,返回两次。根据返回值的不一样判断是在父进程仍是在子进程中执行。父进程返回的是子进程的进程号,子进程返回的是0,若是失败返回-1;blog
3. system函数:进程
建立新的进程调用shell命令,并阻塞当前进程直到shell命令执行完成;内存
不能执行返回127,成功返回进程状态值,失败返回-1;资源
int ret = system("ping www.baidu.com");
4. exec函数族:
exec函数会建立新的进程,并替换当前进程的资源,所以新的进程号依然和原来的进程号相同;
exec函数在执行之后不会返回,由于新的进程资源已经占据了当前进程的资源,包括代码段,数据段和堆栈段等,只有进程调用失败才返回-1;
exec函数一般会在fork以后,在新的子进程中被调用,这样的话,新的进程会占用子进程的资源进行运行;
linux系统采用写时复制,在fork以后若是当即调用exec函数,不会当即复制父进程的资源,而是使用exec的参数来覆盖原有进程。除非发生了原来的内存内容发生改变时,才建立新的物理内存空间;
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char **arg) { pid_t pid = getpid(); pid_t ppid = getppid(); printf("linux net: %d %d \n", pid, ppid); pid_t cpid = fork(); int count = 1; if (cpid > 0) { printf("parent progress: %d %d %d. %d \n", cpid, getpid(), getppid(), count); count = 111; } else if (cpid == 0) { printf("child progress: %d %d %d. %d \n", cpid, getpid(), getppid(), count); count = 222; int ret = execvp("./net-exe-test", 0); printf("exec ret %d \n", ret); } else { printf("create progress failed. \n"); } printf("---------------------1 pid %d count %d \n", getpid(), count); getchar(); return 0; }