1.进程的PCB块
2.进程的虚拟地址空间mm_struct
3.进程的页表
这三个一起才算完成了进程的创建!
进程调用fork,当控制转移到内核中的fork代码后,
内核做:
1.分配新的内存块和内核数据结构给子进程
2.将父进程部分数据结构内容拷贝至子进程
3.添加子进程到系统进程列表当中
4.fork返回,开始调度器调度
通常,父子代码共享,父子再不写入时,数据也是共享的
子进程返回0,
父进程返回的是子进程的pid
通常,父子代码共享,父子再不写入时,数据也是共享的,当任意(是任意一方!)一方试图写入,便以写时拷贝的方式各自一份副本
因此发生写时拷贝后表面上看父子进程还是指向同一个地址同一个空间,其实子进程的地址已经被页表映射到其他地方去了!!
1.一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子进程来处理请求。
2.一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数
1.系统中有太多的进程
2.实际用户的进程数超过了限制
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止
正常终止(可以通过 echo $? 查看进程退出码):
1.从main返回
2.调用exit
3._exit
首先需要了解进程退出OS做了些什么
#include
#include
#include
#include
#include
#define NUM 128
#define CMD_NUM 64
int main()
{
char command[NUM];
for( ; ; ){
char *argv[CMD_NUM] = { NULL };
//1. 打印提示符
command[0] = 0; //用这种方式,可以做到O(1)时间复杂度,清空字符串
printf("[who@myhostname mydir]# ");
fflush(stdout);
//2. 获取命令字符串
fgets(command, NUM, stdin);
command[strlen(command) - 1] = '\0'; //"ls\n\0"
//printf("echo: %s\n", command);
//"ls -a -b -c\0";
//3. 解析命令字符串, char *argv[];
//strtok();
const char *sep = " ";
argv[0] = strtok(command, sep);
int i = 1;
while(argv[i] = strtok(NULL, sep)){
i++;
}
//4.检测命令是否是需要shell本身执行的,内建命令
if(strcmp(argv[0], "cd") == 0){
if(argv[1] != NULL) chdir(argv[1]);
continue;
}
//5. 执行第三方命令
if(fork() == 0){
//child
execvp(argv[0], argv);
exit(1);
}
int status = 0;
waitpid(-1, &status, 0);
printf("exit code: %d\n", (status >> 8)&0xFF);
//for(i=0; argv[i]; i++){
// printf("argv[%d]: %s\n", i, argv[i]);
//}
}
}