进程和程序的区别:
程序是一段静态的代码,是保存在非易失储存器上的制令和数据的有序集合,没有任何执行的概念;而进程是一个动态的概念,它是程序的一次执行过程,包括了动态创建、调度、执行和消亡的整个过程,他是程序执行和资源管理的最小单位。可以用一个程序创建许多进程。或者反过来说,许多进程运行的可以是同一程序
fork函数,fork函数能复制整个父进程的所有代码,但不同的是其访问的实际物理地址和父进程不通,子进程虽然复制了父进程的所有代码,但实际执行的是fork()函数以下的部分,若当前进程是父进程则返回值大于零,否者返回值等于零
简单的fork函数伪代码:
#include <unistd.h>pid_t fork(void) {// 创建一个新的进程// 复制父进程的内存空间,包括代码、数据、堆栈等,采用写时复制技术if (/* 当前进程是子进程 */) {return 0; // 返回0表示这是子进程} else if (/* 当前进程是父进程 */) {return child_pid; // 返回子进程的进程ID} else {return -1; // 表示fork失败}
}
fork函数运用代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main(int argc, const char *argv[]){pid_t pid;printf("我是父进程我正准备创建一个子进程\n");pid = fork();//创建一个子进程if(pid == -1){printf("进程创建失败\n");}else if(pid > 0){printf("我是父进程已经成功创建子进程编号为: %d\n", pid);}else if(pid == 0){printf("我是子进程\n");}return 0;
}
getpid获取进程自身ID,getppid获取进程父进程的ID
检验地址使用关系代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main(int argc, const char *argv[]){int cnt = 0;pid_t pid;printf("我是父进程我正准备创建一个子进程\n");pid = fork();//创建一个子进程if(pid == -1){printf("进程创建失败\n");}else if(pid > 0){cnt = cnt + 1; printf("我是父进程已经成功创建子进程编号为: %d\n", pid);printf("CNT: %d,address: %p\n", cnt , &cnt);}else if(pid == 0){cnt = cnt + 1;printf("我是子进程我的编号为%d,我的父进程编号%d\n", getpid(), getppid());printf("CNT: %d,address: %p\n", cnt , &cnt);}return 0;
}
可以看出父子进程,输出cnt的地址都是一样的,说明父子进程都用的一个虚拟地址,但是cnt输出却都是1说明两者cnt的物理地址不一样
exec提供了,可以在一个进程中执行另一个进程的方法
vfork子进程与父进程公用相同物理地址
exit执行后会刷新缓存区_exit不会
孤儿进程:
父进程结束而子进程仍然未退出,此时子进程会被init进程收养
僵尸进程:
如果父进程不退出,子进程退出,此时父进程不会主动回收子进程资源,子进程会成为僵尸态。
wait函数可用于阻塞父进程,在使用wait函数的时候,其会等待子进程退出,一旦子进程退出,则wait函数会立即返回,并获得子进程的退出时的状态值,并回收子进程使用的各种资源,以避免子进程成为僵尸态
如果父进程创建了多个子进程,那么任意进程结束wait函数都会结束,对于waitpid函数,它能检测特定子进程的状态且能非阻塞回收资源等等