Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2090910
  • 博文数量: 249
  • 博客积分: 1305
  • 博客等级: 军士长
  • 技术积分: 4733
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-17 10:37
个人简介

不懂的东西还有很多,随着不断的学习,不懂的东西更多,无法消灭更多不懂的东西,那就不断的充实自己吧。 欢迎关注微信公众号:菜鸟的机器学习

文章分类

全部博文(249)

文章存档

2015年(1)

2014年(4)

2013年(208)

2012年(35)

2011年(1)

分类: C/C++

2013-07-24 16:00:29


    今天在看《UNIX环境高级编程》,看到关于fork函数的时候,看到一个相应的实例,不仅可以对fork的理解加深,还可以了解到与缓冲区相关的内容,特意整理在这里,以后看看。
    具体的代码如下所示。
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>

  4. int glob = 6;
  5. char buf[] = "a wirte to stdout\n";

  6. int main()
  7. {
  8.     int var;
  9.     pid_t pid;
  10.     
  11.     var = 88;

  12.     if(write(STDOUT_FILENO, buf, sizeof(buf) - 1) != sizeof(buf) - 1)
  13.     {
  14.         printf("write error.\n");
  15.         exit(1);
  16.     }

  17.     printf("before fork\n");

  18.     if( (pid = fork() ) < 0)
  19.     {
  20.         printf("fork error.\n");
  21.         exit(1);
  22.     }
  23.     else if(pid == 0)
  24.     {
  25.         glob++;
  26.         var++;
  27.     }
  28.     else
  29.     {
  30.         sleep(2);
  31.     }

  32.     printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
  33.     exit(0);
  34. }
    运行结果如下所示。
    
    从上面的结果可以看出:
    (1)子进程的结果发生了变化,而父进程的数据没有发生变化;
    (2)输出到终端与输出到文件中的结果不一样;
   
     对于(1)的解释如下
    子进程和父进程继续执行fork调用之后的指令。子进程是父进程的副本。例如子进程获取进程数据空间、堆和栈的副本。注意:这是子进程所拥有的副本。父、子进程并不共享这些存储空间。记住:不共享这些存储空间。
    所以才有了上面(1)的结果:子进程的变量值改变了,而父进程的变量值没有变化。

    对于(2)的解释如下:
    首先,上面的关于父子进程的输出顺序是不确定的。一般来说,在fork之后是先执行父进程还是子进程是不确定的。这取决于内核所使用的调度算法。如果要求父子进程同步,则要求某种形式的进程间通信(这是后话)。在上面的程序中,父进程使自己先休眠2秒钟,以使子进程先执行。但并不保证2秒钟已经足够。
    当写到标准输出时,我们将buf减1作为输出字节数,这是为了避免将终止null字节写出。strlen计算不包含终止null字节的字符串长度,而sizeof则计算包括终止null字节的缓冲区长度。两者之间的另一个差别是:使用strlen需要一次函数调用,而对于sizeof,因为缓冲区已经用已知的字符串进行了初始化,其长度是固定的,所以sizeof在编译时计算缓冲区的长度。
    上面的是题外话,与上述显示结果没有关系,现在进入正题哈。
    注意上面程序中fork与I/O函数之间的交互关系。write函数是不带缓冲的。因为在fork之前调用了write,所以其数据写到标准输出一次。但是,标准I/O库是带缓冲的。
    如果标准输出连接到终端设备,则它是行缓冲的,否则它是全缓冲的。
    当以交互的方式运行该程序时,只得到该printf输出的行一次,其原因是标准输出缓冲区由换行符冲洗。但是当标准输出重定向到一个文件时,却得到printf输出行两次。其原因是:在fork之前调用了printf一次,当调用fork时,该行数据仍然在缓冲区中,然后在将父进程数据空间复制到子进程中时,该缓冲区也被复制到了子进程中。于是,那时父、子进程各自有了带该行内容的标准I/O缓冲区。在exit之前的第二个printf将其数据添加到现有的缓冲区中。当每个进程终止时,最终会冲洗缓冲去的副本。
    






阅读(1231) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~