目录
一、学习的知识点
fork函数
fork函数产生两个进程,一个是主进程,也就是父进程,另一个是子进程。有两个返回值,一个返回值大于0,表示父进程,值为子进程的pid。一个返回值等于0,表示子进程。
变量的变化
fork以后,子进程对父进程 RW段(已初始化) BSS段(未初始化)的数据遵循写时拷贝,有改动时才执行拷贝,而RO段的数据是共用的
文件描述符的变化
fork前open的文件,fork后的子进程后父进程都有相同的文件描述符,但fork后open的文件只有执行open的进程才有对应的文件描述符。我的理解是文件描述符可以继承但不是共享的。
1.1僵尸状态
一个子进程结束运行时,父进程还存在
- 子进程进入僵尸状态,因为进程结束的返回码还需要给父进程 exit(0)
- 子进程不再活跃(不执行逻辑),但是资源无法释放(CPU/内存/数据)
- 以上总结说明 程序操作的时候不希望出现 僵尸状态的情况。
1.2孤儿
父进程先于子进程结束
- 父进程没了PID消失,父进程的所有子代进程都属于孤儿进程
- 父进程吧子进程托孤给系统管理
- 以上总结说明 程序操作的时候不希望出现。
1.3如何避免僵尸进程
1.3.1 wait
pid_t wait(int *status);
wait函数用于使父进程阻塞,只能让父进程等待子进程,不能使子进程等待父进程。
wait的返回值,如果等待成功 返回等待的pid号,出错则返回-1。
status参数 用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:pid = wait(NULL);
wait函数特点
- 如果有多个子进程在运行,那么wait函数只会等待先结束的子进程
1.3.2 waitpid
pid_t waitpid(pid_t pid, int * status, int options) ; 等待某个指定的子进程。等待进程ID为pid的进程
- pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。
- pid > 0 等待其进程I D与p i d相等的子进程。
- pid == 0 等待其组I D等于调用进程的组I D的任一子进程。
- pid < -1 等待其组I D等于p i d的绝对值的任一子进程。
2 execlp
在子进程里调用另外一个程序
execl系列函数的作用就是可以在你创建的子进程中调用其他人写好的可执行程序
execlp是替换进程映像 相关函数只要调用,后面的代码都不会执行 +p会导入系统的环境变量
execlp(“ls”, “ls -l”, NULL);
execlp(“ps”,“ps”,"-ax",0);
守护进程
概念:程序一旦启动就会转入后台,不会因为关闭终端而结束进程
- 最重要的特性是后台运行
- 如果你要脱离终端运行,首先要创建一个新的会话 创建会话函数 setsid();
- 默认情况下 父进程不能创建会话
- 创建的守护进程不要使用 printf、cout等输出函数。因为脱离终端 而字符输出依赖于终端 所以输出了也看不见
- 在Linux中 输入输出都有设备 他有专门的文件描述符 0 1 2错误输出
- 所以创建完守护进程后 也要分别关闭 close(0) close(1) close(2)
- 在默认程序后
- 一个终端可以运行很多进程 多个进程会组成会话 session 会话有权利创建终端
- 一个进程可以产生子进程,产生多个子进程 为进程组 默认情况下父进程就是进程组组长
void create_deamons()
{
pid_t pid = fork();
if (pid == 0)
{
setsid();//因为父进程默认是进程组组长,所以不允许调用setsid函数来创建会话
//子进程成功创建了会话,默认称为会话的领导者,这个会话领导者有一个权力:可以创建一个新的终端
pid = fork();
if (pid == 0)
{
//while循环要替换成守护进程的功能代码段
while (1)
{
sleep(1);
}
//再创建一个子进程的时候,这个子进程不是会话组组长他就没有权力创建新的进程,真正脱离了终端运行
//这里面的代码才是真正的守护进程代码
}
_exit(0);
}
else if (pid > 0)
{
_exit(0); //要写在父进程中 否则子进程会被杀死
}
}
for(int i =0;i<=2;i+)
{
close(i);
}
//关闭键盘 显示器 错误输出(并不是一定 一般规则如此)
二、上课没有听懂或者没有理解的地方
无
三、当天学习的收获
避免僵尸进程