• Linux学习之“fork函数”


    n返回值:
    fork函数调用一次,但是返回两次:在子进程中返回0,在父进程中返回子进程ID,出错返回-1。通过返回值,可以确定是在父进程还是子进程中。
    n子进程和父进程继续执行fork调用之后的指令。
    子进程是父进程的副本:
    1.子进程获得父进程数据空间、堆和栈的副本;父子进程并不共享这些存储空间。
    2.父子进程共享正文段(只读的);
    3.为了提高效率,fork后并不立即复制父进程空间,采用了COW(Copy-On-Write);当父子进程任意之一,要修改数据段、堆、栈时,进行复制操作,但仅复制修改区域
    看一个程序:
    复制代码
    #include<iostream>
    #include<unistd.h>
    #include<stdio.h>

    using namespace std;

    int glob = 6;
    char buf[] = "a write to stdout ";

    int main(void)
    {
    int var;
    pid_t pid;

    var = 88;

    if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
    {
    cout << "write error" << endl;
    return 0;
    }

    printf("before fork ");

    if ( (pid = fork()) < 0)
    {
    cout << "fork error" << endl;
    return 0;
    }
    else if (pid == 0)
    {
    glob++;
    var++;
    }
    else
    {
    sleep(2);
    }

    printf("pid = %d, glob = %d, var = %d ", getpid(), glob, var);

    return 0;
    }
    复制代码
    直接输出到控制台:
    a write to stdout
    before fork
    pid = 1867, glob = 7, var = 89
    pid = 1866, glob = 6, var = 88
    使用重定向“./a.out>a.txt”,a.txt内容如下:
    a write to stdout
    before fork
    pid = 1939, glob = 7, var = 89
    before fork
    pid = 1938, glob = 6, var = 88
    为什会有这个差别?
    先来看下“STDOUT_FILENO”和“FILE *stdout”的区别:
    stdin / stdout / stderr是FILE*类型,供标准C++一级提供的文件操作函数库使用,定义在头文件<stdio.h>中。
    STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO 是int类型,其实质是文件描述符(值分别为0,1,2),定义在头文件<unistd.h>中。
    FILE * stdin / stdout / stderr 对应的文件描述符(fd)分别是 STDIN_FILENO(0) / STDOUT_FILENO(1) / STDERR_FILENO(2) 。
    两者的差别主要是标准I/O是带缓冲(具体见下面说明)的,而STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO是不带缓冲的。
    我们只需记住:
    使用stdin / stdout / stderr的函数主要有:fread、fwrite、fclose等,基本上都以f开头。
    使用STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO的函数有:read、write、close等。
    关于两者更详细的说明:
    1.“FILE *stdout 和 STDOUT_FILENO 的区别”(http://hi.baidu.com/_%C2%B7_%C8%CB_%BC%D7_/blog/item/2d84a816882fdbd4c2fd78e1.html)
    2."对stdin,stdout 和STDOUT_FILENO,STDIN_FILENO的学习"(http://www.cnblogs.com/hoys/archive/2011/05/11/2043044.html)
    下面看下关于"printf"/"write"和缓冲的说明:
    printf是在stdio.h中声明的函数,而标准IO都是带缓冲的,所以printf是带缓冲的。而write则是不带缓冲的。
    标准IO在输入或输出到终端设备时,它们是行缓冲的,否则(文件)它们是全缓冲的。而标准错误流stderr是不使用缓冲的。更为准确的描述是:当且仅当标准输入和标准输出并不涉及交互式设备使,他们才是全缓冲的。标准出错流不使用缓冲。
    下列情况会引发缓冲区的刷新(清空缓冲区):
    1、缓冲区满时;
    2、执行flush语句;
    3、执行endl语句(printf是" ");
    4、关闭文件
    综上所述,write的内容在父进程直接输出到了设备,“before fork”在主线程输出到终端后因为换行符而清空了缓冲区,所以也只输出了一次。
    而重定向到"a.txt"时,printf使用的是全缓冲,所以“before fork”并未输出到设备,而是随着fork()而被复制了一份到子进程的空间中,所以输出了两次。
    注意:在重定向父进程输出时,子进程也被重定向了。
  • 相关阅读:
    C Socket编程之Connect超时 (转)
    【c#】设置Socket连接、接收超时(转)
    socket测试远程地址能否连接并为连接设置超时(转)
    ZedGraph右键菜单怎样禁止它弹出(转)
    赚钱本身就是人生目的
    如果一个女人喜欢你,又不跟你在一起,而且只跟你很暧昧,那代表什么
    LayoutInflater的使用
    Android应用程序的生命周期
    Android的系统服务一览
    Android系统服务-简介
  • 原文地址:https://www.cnblogs.com/zhangyubao/p/7016917.html
Copyright © 2020-2023  润新知