• 关于linux多线程fork的理解和学习


      fork在英文中是“分叉”的意思。为什么取这个名字呢?因为一个进程在运行中,如果使用了fork函数,就产生了另一个进程,于是进程就“分叉”了,所以这个名字取得很形象。下面就看看如何具体使用fork函数,这段程序演示了使用fork的基本框架。
     
    函数声明:
     
    pid_t fork();
     
      fork函数用于产生一个新的进程,函数返回值pid_t是一个整数,在父进程中,返回值是子进程编号,在子进程中,返回值是0。
     
    复制代码
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
     
    int main()
    {
      printf("本程序的进程编号是:%d\n",getpid());
     
      int ipid=fork();
     
      sleep(1);       // sleep等待进程的生成。
     
      printf("pid=%d\n",ipid);
     
      if (ipid!=0) printf("父进程编号是:%d\n",getpid());
      else printf("子进程编号是:%d\n",getpid());
     
      sleep(30);    // 是为了方便查看进程在shell下用ps -ef|grep book252查看本进程的编号。
    }
    复制代码
       
    从 fork() 这个函数开始出现后,
    便创建了子进程,并且子进程和父进程一样从fork(这个函数一起执行下去,也就是说从fork()开始的下面所有代码分别被父
    进程和子进程都执行了一次,如果没有条件判断语句判别fork()的返回值,将无法分别子父进程,根据fork()的返回值可以令子父进程跳过或执行某条语句

    运行结果

     

     

    初学者可能用点接受不了现实。

    1)一个函数(fork)返回了两个值?

    2)if和else中的代码能同时被执行?

    那么调用这个fork函数时发生了什么呢?fork函数创建了一个新的进程,新进程(子进程)与原有的进程(父进程)一模一样。子进程和父进程使用相同的代码段;子进程拷贝了父进程的堆栈段和数据段。子进程一旦开始运行,它复制了父进程的一切数据,然后各自运行,相互之间没有影响。

    fork函数对返回值做了特别的处理,调用fork函数之后,在子程序中fork的返回值是0,在父进程中fork的返回是子进程的编号,程序员可以通过fork的返回值来区分父进程和子进程,然后再执行不同的代码。

     

    复制代码
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    void fatchfunc() // 父进程流程的主函数
    {
      printf("我是老子,我喜欢孩子他娘。\n");
    }
    
    void childfunc() // 子进程流程的主函数
    {
      printf("我是儿子,我喜欢西施。\n");
    }
    
    int main()
    {
      if (fork() > 0)
      {
        printf("这是父进程,将调用fatchfunc()。\n");
        fatchfunc();
      }
      else
      {
        printf("这是子进程,将调用childfunc()。\n");
        childfunc();
      }
    
      sleep(1);
      printf("父子进程执行完自己的函数后都来这里。\n");
      sleep(1);
    }
    复制代码

     

     

    运行结果:

     

     

    在上文上已提到过,子进程拷贝了父进程的堆栈段和数据段,也就是说,在父进程中定义的变量子进程中会复制一个副本,fork之后,子进程对变量的操作不会影响父进程,父进程对变量的操作也不会影响子进程。

     

    复制代码
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
     
    int i=10;
     
    int main()
    {
      int j=20;
     
      if (fork()>0)  //从 fork() 这个函数开始出现后,
                      //便创建了子进程并且和父进程一样从fork()
                      //这个函数一起执行下去,也就是说从fork()开始的下面所有代码分别被父///进程和子进程都执行了一次,如果没有条件判断语句判别fork()的返回/////值,将无法分别子父进程,根据fork()的返回值可以令子父进程跳过或执///行某条语句
    
      {
        //如果fork大于零,证明是父进程,即执行下面的语句
        
        i=11;j=1; sleep(1);  printf("父进程:i=%d,j=%d\n",i,j);
        int sum = i + j;
        printf("父sum = %d\n",sum);
    
      }
      else
      {
        //如果fork小于零,证明是子进程,执行下面的语句
        i=12;j=22; sleep(1);  printf("子进程:i=%d,j=%d\n",i,j);
        printf("子sum = %d\n",i+j);
    
      }
    }
    复制代码
     
     
    从 fork() 这个函数开始出现后,便创建了子进程,并且子进程和父进程一样从fork(这个函数一起执行下去,也就是说从fork()开始的下面所有代码分别被父
    进程和子进程都执行了一次,如果没有条件判断语句判别fork()的返回值,将无法分别子父进程,根据fork()的返回值可以令子父进程跳过或执行某条语句

    运行结果

     

     

     

     

    来源:www.freecplus.net

    作者:码农有道

     

    作业:

    (1)编写一个多进程程序,验证子进程是复制父进程的内存变量,还是父子进程共享内存变量?

     

    复制内存变量

     

     

     

    2)编写一个示例程序,由父进程生成10个子进程,在子进程中显示它是第几个子进程和子进程本身的进程编号。

    复制代码
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main()
    {
      int i = 0;
      while (i < 10)
      {
    
        if (fork() > 0) 
        {
          i++;
          continue; //父进程回到while(循环),
        }
        else
        {
          printf("子进程第%d个,pid = %d\n", i, getpid());
          break;
        }
      }
      sleep(10);
    
      return 0;
    }
    复制代码

     

    运行结果

     

     

     

     

     

     

    3)编写示例程序,由父进程生成子进程,子进程再生成孙进程,共生成第10代进程,在各级子进程中显示它是第几代子进程和子进程本身的进程编号。

     

    如图

    复制代码
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main()
    {
      int i = 0; //全局变量,计数器,计算第几代子进程
      while (i < 10)
      {
    
        if (fork()== 0)
        {
          i++;
          continue;
        }
        else
        {
          printf("第%d代子进程,pid = %d\n", i, getpid()); 第 0 代子进程是第一个父进程
        
          break;
        }
      }
      sleep(10);
    
      return 0;
    }
    复制代码

     

    运行结果:

    子进程是下一个子进程的父进程

     

     

     

    4)利用尽可能少的代码快速fork出更多的进程,试试看能不能把linux系统搞死。

     

    复制代码
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    int main()
    {
      int i = 0; //全局变量,计数器,计算第几代子进程
      while (i < 10)
      {
    
        if (fork()>0)
        {
          fork();
          
        
          
        }
      }
      printf("pid=%d",getpid());
    
      return 0;
    }
    复制代码

     

     

     

     

     

    5)ps -ef |grep book251命令是ps和grep两个系统命令的组合,各位查一下资料,了解一下grep命令的功能,对程序员来,grep是经常用到的命令。

     

     https://blog.csdn.net/weixin_52273136/article/details/110451596

     

     

    来源:C语言技术网(www.freecplus.net

    作者:码农有道

     

     

  • 相关阅读:
    面试突击58:truncate、delete和drop的6大区别
    SpringSecurity(二十一)--OAuth2:实现资源服务器(中)实现带有JdbcTokenStore的黑板模式
    uView学习(持续更新中)
    ROS-serial串口包的数据原始模式使用方法
    超强预测算法:XGBoost预测模型
    预提交和 Git Hooks:自动化高质量代码
    Cmd中的一些命令
    【CSS 画个梯形】
    笔记(下):mysql-DuplicateUpdate和java的threadpool的“死锁“
    php上传图片,yii上传图片,(base64上传)
  • 原文地址:https://www.cnblogs.com/dhua/p/16271364.html