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的进程)作为他的父进程,但是这样会一直消耗系统资源。

所以一定要当心僵死进程!!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值