功能: 主要用于以复制当前正在调用进程的方式创建新进程,其中新创建出来的进程叫做子进程,当前正在调用的进程叫做父进程;
返回值 success —- 父进程返回子进程的进程号,子进程返回0,error —- 父进程返回-1,没有子进程;
注意: 使用fork()创建子进程之后,父子进程的执行先后次序由操作系统的调用算法决定;
a. 对于fork()调用之前的代码来说,父进程执行一次; b. 对于fork()调用之后的代码来说,父子进程各自执行一次; c. 对于fork()调用的返回值来说,父子进程各自返回一个,其中父进程返回子进程的进程号,子进程返回0;
a. 父进程启动了子进程,父子进程同时执行,如果子进程先于父进程结束,会给父进程发信号,父进程负责回收子进程的资源; b. 如果父进程先结束,则子进程就会变成孤儿进程,此时子进程会变更父进程(一般认定init(1)为新的父进程),init进程收养了孤儿进程,因此被叫做孤儿院进程; c. 如果子进程先结束,但是由于各种原因父进程没有收到子进程发来的信号,也就不能回收子进程的资源,此时子进程就会变成僵尸进程;
使用fork()创建子进程后,子进程会复制父进程中除了代码区之外的其他内存区域,而代码区和父进程共享; 使用fork()创建子进程后,子进程会复制父进程中的文件描述符总表,但不会复制文件表等数据结构,因此父子进程对应的是同一个文件表结构;
扩展: a. 如何创建3个新进程总共变成4个进程??? fork();fork(); 4个进程:1个父进程+2个子进程+1个孙子进程 b. 如何创建2个新进程总共变成3个进程??? pid_t pid = fork(); if(pid > 0) { fork(); } 3个进程:1个父进程+2个子进程 c. while(1){fork();}被称为fork()炸弹;a. 执行了main()中的return语句; b. 调用exit()终止进程; c. 调用_exit() / _Exit()终止进程; d. 最后一个线程返回; e. 最后一个线程调用了pthread_exit();
a. 采用信号终止进程; b. 最后一个线程被其他线程取消;
功能: 主要用于立即终止当前正在调用的进程,在终止的同时,会关闭所有属于该进程的文件描述符;让该进程的所有子进程变更父进程为init进程;给该进程的父进程发送SIGCHLD信号; 参数status的数值主要用于返回给父进程作为当前进程的退出状态信息,若父进程想要获取该退出状态信息,则需要调用wait系列函数中的一个; The function _Exit() is equivalent to _exit().
#include <stdlib.h> void exit(int status);功能: 主要用于引起正常进程的终止,参数status & 0377的结果会被返回给父进程,作为当前进程的退出状态信息,父进程若要获取该信息,也得调用wait系列函数中的一个; 该函数在终止进程时,会引起atexit()和on_exit()所注册(单独保存)函数的调用;
#include <stdlib.h> int atexit(void (*function)(void));功能: 主要用于注册(单独保存)参数指定的函数,该函数会在正常进程终止时被调用,而正常终止进程的方式主要有两种:a. 调用exit(); b. 执行了main()中的return;
返回值: success —- 0,error —- 非0;
#include <stdlib.h> int on_exit(void (*function)(int , void *), void *arg);功能: 主要用于注册参数指定的函数,该函数会在正常进程终止时被调用。on_exit()能够将指针类型参数arg传递给函数function()
返回值: success —- 0,error —- 非0;
The call wait(&wstatus) is equivalent to: waitpid(-1, &wstatus, 0);
扩展: 重定义在同一个作用域中定义多个相同变量。
练习: vi 08waitpid.c文件,首先创建两个子进程,子进程一先开始执行,睡眠10秒后终止,调用exit(100); 然后子进程二开始执行,睡眠20秒后终止,调用exit(200); 父进程等待任意一个子进程终止,并获取退出状态信息,最后打印出来;
明天预报: (1)进程的管理 (2)信号的处理