• Linux中的fork函数


    操作系统实验二

    fork函数

    作用

    fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程

    返回值

    • 负值:创建子进程失败。
    • 零:返回到新创建的子进程。
    • 正值:返回父进程或调用者。该值包含新创建的子进程的进程ID
      image

    用法

    pid_t pid=fork();如果创建成功,会有两个进程:父进程和子进程,fork在这两个进程中分别返回,就是返回两次且返回值不同。

    一段程序

    # include<stdio.h>
    # include<sys/types.h>
    # include<unistd.h>
    
    int main()
    { 
      int pid1, pid2;
      printf("I am father %d! My father is %d.\n", getpid(), getppid());
      if ((pid1 = fork())<0) //fork return value < 0 , create failed
      {
        printf("Child1 fail create!\n");
        return 1;
      }
      else if (pid1 == 0)  //fork return value = 0, son is running
      {
        printf("I am son %d! My father is %d. \n", getpid(), getppid());
        return 0;
      }
      if ((pid2 = fork())<0)
      {
        printf("Child2 fail create!\n");
        return 0;
      }
      else if (pid2 == 0)
      {
        printf("I am daughter %d! My father is %d.\n", getpid(), getppid());
        return 0;
      }
    }
    

    编译运行

    gcc fork.c -o fork
    ./fork
    

    运行结果
    image
    分析: 首先是父进程,打印了它的身份和进程号,还有它的父进程号
    在第一个if语句中创建了子进程,子进程创建成功,返回值是0,执行第一个else if,打印身份是子进程和它的进程号和父进程号。
    父进程的fork返回值是子进程号大于0,不满足第一个条件,顺序往下执行,在第二个if里创建了一个进程。
    子进程创建成功,返回值是0,执行else if,打印身份、进程号和父进程号。
    daughter进程的父进程号时884,是因为父进程已经运行结束了,daughter进程找不到原来的父进程,变成了孤儿进程,被其他进程收养了。
    image
    分析: 有时daughter进程和son进程顺序不一样是因为父进程比son进程执行的快,先创建了daughter进程,daughter进程先进行了打印。
    打印在命令行上的原因:
    处理父进程、son进程、daughter进程,还有一个shell进程,shell进程就是用户和linux交互的进程,用于解析输入的命令行。这四个进程都要抢占屏幕这个资源,如果被shell先抢占了,就会出现命令行,其他进程输出就会在命令行上了。(不知道理解的对不对。。。)

    孤儿进程

    父进程运行结束后,它创建的子进程还在运行,这些子进程就会成为孤儿进程。
    避免出现孤儿进程: 在父进程运行最后加上sleep(1),父进程不会运行那么快,保证子进程先退出。
    image

    lockf函数

    参考:https://blog.csdn.net/qq_24421591/article/details/49104455

    用处

    实现资源的互斥访问

    例子

    # include<stdio.h>
    # include<sys/types.h>
    # include<unistd.h>
    
    int main(){
        int pid1, pid2;
        pid1=fork();
        if(pid1 == 0)
        {
            for(int i = 0; i < 5; i ++ )
            {
                lockf(1,1,0); 	//加锁
                printf("I am son %d\n",i);
                lockf(1,0,0); //解锁
                sleep(3); //等待3s
            }
        }
        else
        {
            pid2=fork();
            if(pid2 == 0)
            {
                for(int i = 0; i < 5; i ++ )
                {
                    lockf(1,1,0);
                    printf("I am daughter %d\n",i);
                    lockf(1,0,0);
                    sleep(3);
                }
            }
            else
            {
                printf("I am father\n");
            }
        }
    	return 0;
    }
    

    image
    分析: 临界资源是屏幕,son进程和daughter进程会交替打印,是因为在循环中打印过后,会等待3s,在等待的时间里,另一个进程就是抢占资源,进行打印。
    对比
    将sleep(1)放在解锁之前,这样即使进程在sleep,其他进程也没有机会抢占资源。
    image

    作者:inss!w!
    版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 相关阅读:
    [Linux]history 显示命令的运行时间
    android从中国天气网获取天气
    R语言做文本挖掘 Part4文本分类
    ACdreamoj1110(多重背包)
    9.6 第九章小结
    role &#39;PLUSTRACE&#39; does not exist
    分糖果
    启动嵌入式间:资源有限的系统启动
    SDL2来源分析7:演出(SDL_RenderPresent())
    C# DataGridView绑定数据源的几种常见方式
  • 原文地址:https://www.cnblogs.com/Hfolsvh/p/15684878.html
Copyright © 2020-2023  润新知