zoukankan      html  css  js  c++  java
  • fork()的一些测试

    这篇随笔也是看到陈皓的这篇文章自己做了一些测试和学习,http://coolshell.cn/articles/7965.html

    1. 两个fork程序 

    关于fork,先看我们的第一个fork测试程序

     1 #include<stdio.h>
     2 #include<unistd.h>
     3 int main(){
     4     for(int i=0; i<2; i++){ 
    6
    int result = fork(); 7 if(result == 0){ 8 printf("child process -----"); 9 }else if(result > 0){ 10 printf("parent process: child id = %d---------", result); 11 } 12 printf("ppid : %d---pid : %d---i=%d\n", getppid(), getpid(), i); 13 } 14 int n; 15 sleep(10); 16 }

    如果fork()成功,在父进程中,fork()返回子进程的pid,在子进程中返回0, 失败则返回-1。程序的最后sleep了10s, 在这10s当中,其实几乎是4个进程同时在sleep。这时用pstree查看一下,可以看到如下情况

    bash是我运行./fork的那个shell,可以去想像一下这个过程,在i为0和1的时候,分别是到了哪个情况。    运行结果如下

    可以看到各个进程交替执行的情况是怎样的。

    我们再来看一下第二个fork()程序,做了一些改动

     1 #include<stdio.h>
     2 #include<unistd.h>
     3 int main(){
     4     for(int i=0; i<2; i++){
     5         int result = fork();
     6         printf("& %d  ", getpid());
     7     }
     8     sleep(5);
     9     printf("\n");
    10 }

    猜猜会打出几个&, 不会是6个,实际上是8个。因为printf是有buffer的,而一个进程的buffer也会随着fork被复制的(库函数的buffer是在user-space中的),直到第9行遇到 "\n"时,进程的buffer才会被flush掉。 运行的结果是在sleep之后才会打印出所有的东西,也说明了这一点。  以下是运行结果

    对照着sleep时pstree的情况来看

    对着代码去想一想那个过程,./for一运行起来,最终会产生4个进程,上面那个图右边那一栏就是这4个进程的id, 可以看到后两行的左边的那个&就是父进程(可以看到打出&时的进程id)打出的,通过buffer复制过来的。

    2。设备文件(device file),有缓存的(buffered)和没有缓存的(unbuffered)

    device file分为块设备文件(block device)和字符设备文件(character device file),设备文件的定义这里引用一下wiki上的定义,http://en.wikipedia.org/wiki/Device_file。device file or special file is an interface for a device driver that appears in a file system as if it were a file。也就是程序可以用标准的IO system call和device driver进行交互。字符设备文件没有缓存,块设备文件是有缓存的.

    c标准库中定义的stderr就是一个字符设备的FILE*, 而stdout是一个块设备的FILE*,在C库中,FILE是一个struct,它用来标识一个stream并保存这个stream相关的信息,如pointer to its buffer,position indicator等(注意stream即流的概念并不是属于语言的)。stderr没有缓存,stdout有缓存,通过下面的程序可以验证。

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 int main()  
     4 {
     5         int i = 0;
     6         while(1)
     7         {
     8                 fprintf(stdout,"hello-std-out");
     9                 fprintf(stderr,"hello-std-err\n");
    10                 sleep(1);
    11                 if(i++ == 5){
    12                     i = 0;
    13                     fflush(stdout);
    14                 }
    15         }
    16         return 0;
    17 }

    13行调用的fflush(FILE*)是stdio.h中声明的函数,如果没有这个调用,8行中打到stdout缓存中的内容都不会被flush出来的。

    在C++的标准io库中,也有类似的情况,标准库中定义的cout,cerr都是类ostream的实例,它们对应于c库中的stdout,stderr。在<iostream>中有如下的声明,但是我没有再在其它的头文件中找到stdout,stderr定义的信息了

    1 extern ostream cout;      /// Linked to standard output
    2 extern ostream cerr;      /// Linked to standard error (unbuffered)

    通过如下的C++程序可以验证cout是buffered, 而cerr是unbuffered。

     1 #include<iostream>
     2 using namespace std;
     3 int main(){
     4     char ch[5] = {'a','b','c','d','e'};
     5     char ch2[5] = {'e','r','r','o','r'};
     6     int i = 0;
     7     while(true){
     8  //       cerr.write(ch2, 5);
     9         cout.write(ch, 5);
    10         cout.put(' ');
    11         sleep(1);
    12         if(i++ == 3){
    13             //cout.flush();
    14             cout.put('\n');
    15             i = 0;
    16         }
    17     }
    18 }

    可以用这个程序测试,对于cout,如果没有13,14行的cout.flush()或者给它一个换行符它是不会从缓存中打到输出的。对于cerr就不会有缓存了,但是比较奇怪的是,好像cerr一有输出,cout的缓存就会被清空一下,这个和c中的stdout,stderr是不一样的,没有明白这是怎么回事。

    3,unix的一点东西

    附上apue中描述unix结构的一幅图,重点是库函数(library of common functions)和系统调用(system call)的关系

    可以看到,内核就是实现系统调用所要的功能,而system call的使用方式就是普通的函数调用,在使用上跟自己定义的函数及库函数没有区别。可能这也是为什么POSIX中相关的标准,只规定了头文件以及头文件要提供的接口(函数),并不区分这个接口是system call还是system call之上的库函数。注意POSIX标准是包括了C标准库的。

    POSIX(http://en.wikipedia.org/wiki/POSIX)是IEEE定义的一系列的标准,用于维护操作系统间的兼容性。对于unix系统,早期的posix只定义了core programming interface,也就是操作系统要提供的服务(函数),现在则扩展了很多,包括command line和scriping interface(基于Korn shell),一些用户级别的程序如awk, 还有一个标准的thread library API,大多数现代操作系统都支持了。这些东西现在都汇集于一个文档 IEEE Std 1003.1-2008  或是叫  POSIX.1-2008

    posix定义的unix系统必需的头文件(required headers)如下, 摘自apue2.2.1。我们上面的fork程序只使用了 <unistd.h>。

    参考:

    POSIX wiki : http://en.wikipedia.org/wiki/POSIX

  • 相关阅读:
    SQL语句:Mac 下 处理myql 不能远程登录和本地登录问题
    react中触发事件实现路由跳转
    Sass代码重用----Sass继承
    react实现点击选中的li高亮
    React中通过状态控制元素显示隐藏的三种方法
    React 页面加载后自动执行onClick事件
    formdata实现图片上传
    formdata实现图片上传
    适用于Ant design的省市区联动JSON数据
    react.js
  • 原文地址:https://www.cnblogs.com/livingintruth/p/2627092.html
Copyright © 2011-2022 走看看