Linux笔记记录1 fork()
=。=突然想起来老师下节课要提问Linux内容了 临时抱抱佛脚看看可能会问的问题。
---------------------------------------------------------------------------------------------------------
首先看一个简单的fork()的使用和其运行结果
一个进程调用fork()函数后,系统给新的进程分配资源(存储数据,堆和栈副本)接着把原进程的值都复制给新进程。
但是并没有共享存储空间只共享正文段。
所以改变子进程的变量并不会影响父进程的变量!他们的变量不共用。
父子进程的执行顺序不固定,所以不要纠结那个进程先执行。
值得注意的是:fork()运行结束才复制了一个子进程。
所以子进程是从fork()后开始执行程序,这里输出的地址都是逻辑地址
它们并不在同一分页,物理地址不相同!!
我们的编译器是通过他们的pid识别父子进程的。
ʅ(´◔౪◔)ʃ上面的栗子可以看出,父子进程fork()的返回值是不一样的
(1)在父进程中,返回创建新子进程的ID。
(2)在子进程中,fork返回0
(3)如果出现错误,返回一个负值。emmm至于为什么会出错,那是因为系统内存不足或者进程数已达上限。
---------------------------------------------------------------------------------------------------------
下面再看一个栗子:
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdio,h>
int main(int argc,char *argv[],char *envp[])
{
int i=0;
for(; i<2;i++)
{
fork();
printf(“a”);
}
}
( ̄▽ ̄")总觉得哪里不对啊,为什么多了两个a
但是如果把输出改成printf(“a\n”);呢
就会变成这样子了。这个输出结果是意料中的
问题就在这个 \n 上了。
我们知道有个神奇的东西叫做数据缓冲区,数据缓冲区里的东西在如下几种情况下会输出到终端
(1)程序结束
(2)遇到\n
(3)刷新函数fflush
(4)缓冲区满
(5)遇到输入函数
当然,如果使用write就直接输出到屏幕。
这个栗子可以看出,父进程进程缓冲区内的数据也被子进程所复制。
---------------------------------------------------------------------------------------------------------
int main()
{
char buff[6] = {0};
int r = open("file",O_RDONLY);
assert( r != -1);
pid_t fpid = fork();
assert( fpid != -1);
if( fpid == 0)
{
read(r,buff,1);
printf("child---%s\n",buff);
sleep(1);
read(r,buff,1);
printf("child---%s\n",buff);
}
else
{
read(r,buff,1);
printf("parent---%s\n",buff);
sleep(1);
read(r,buff,1);
printf("parent---%s\n",buff);
}
close(r);
}
上面的代码,如果先执行fork()再打开文件,结果会截然不同:
好啦 以上代码,又可以得出一个结论,通过fork创建子进程,子进程会会继承父上下文和环境大部分内容的拷贝,也包括我们的文件描述符。
对于在父进程执行fork前打开的文件,子进程与父进程共享文件偏移量。
---------------------------------------------------------------------------------------------------------
子进程有自己的生命周期并可以独立运行。在父进程中使用wait系统调用可以让父进程等待子进程结束,
此时父进程将挂起直到子进程结束,wait返回子进程pid。
通过wait系统调用,就能知道子进程是否结束了。
int main(int argc,char *argv[],char *envp[])
{
char *s = NULL;
int n = 0;
pid_t pid = fork();
assert( pid !=-1);
if(pid == 0)
{
n = 3;
s = "child";
}
else
{
n = 8;
s = "parent";
int val = 0;
pid_t res_id=wait(&val);
if(WIFEXITED(val)) //如果子进程正常结束,它就取一个非0值
{
printf("val = %d\n",WEXITSTATUS(val));
}
}
int i =1;
for(; i <n;i++)
{
printf("s = %s,pid = %d,ppid = %d\n"
,s,getpid(),getppid());
sleep(1);
}
}
上图可以看出来子进程是什么时候通过exit结束的。
当然wait的作用还不止这个,下面要写的才是关键,
(。・`ω´・)敲黑板 注意看
---------------------------------------------------------------------------------------------------------
首先请回顾Linux程序设计 中文第4版的内容!!!!
别懒了 一定要看啊啊啊第401页
当子进程先于父进程前结束,或父进程没有wait获取其退出码会造成僵死进程
注意5783
当父进程在它wait子进程前父进程结束了(假定他没有忽略SIGCLD),
子进程将把init(这个pid为1的进程)作为他的父进程,但是这样会一直消耗系统资源。
所以一定要当心僵死进程!!!